如何在另一个类模板中定义完全专用类的构造函数
How to define constructor of fully-specialized class within another class template
我有一个包含另一个类模板的类模板,并且内部模板具有明确的专用化:
template <typename Outer>
struct ContainingClass {
template <typename T>
struct Rule {
Rule(T value);
// ... other members ...
};
template <>
struct Rule<void> {
Rule();
// ... different members than the non-void Rule<T> ...
};
};
我已经为泛型和专用Rule
定义了构造函数:
template <typename Outer>
template <typename T>
ContainingClass<Outer>::Rule<T>::Rule(T value) { }
template <typename Outer>
ContainingClass<Outer>::Rule<void>::Rule() { }
但是 Clang 不喜欢专用类的构造函数:
error: nested name specifier 'ContainingClass<Outer>::Rule<void>::' for declaration does not refer into a class, class template or class template partial specialization
ContainingClass<Outer>::Rule<void>::Rule() { }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
我对此感到困惑,因为它"引用"ContainingClass<Outer>
,这是一个类(ContainingClass
类模板的实例)。 我怀疑我需要为此更改语法中的某些内容,但不清楚是什么。 如何定义此构造函数?
(如果我删除ContainingClass
并将Rule
放在命名空间范围内,它可以工作,但我需要在Rule
中具有其他取决于Outer
类型的东西。 我可以给Rule
它自己的Outer
模板参数,但这会使使用此类的代码更加尴尬,所以如果可能的话,我想避免使用它。 我知道我可以在Rule
类主体中内联定义构造函数,但我想了解为什么单独的定义不起作用。
为了以防万一,我在 Ubuntu 19.04 中使用了 Clang 8.0,在 Mac 上使用 Apple 的"clang-1001.0.46.4"。 (我也尝试过 Ubuntu 的 GCC 8.3,但由于 GCC 错误 #85282 —struct Rule<void>
本身定义的"非命名空间范围内的显式专用化",这在不同的地方失败了。
编辑澄清:我的错误不是关于ContainingClass
内有template <> struct Rule<void>
专业化。 这是 C++14 限制(缺陷 CWG 727)的主题,通过添加虚拟模板参数来解决,因此模板只是部分而不是完全专用的。 我相信限制已经在 C++17 中解除,并且Rule
类本身的专业化在 Clang 中运行良好(尽管 GCC 有错误)。 所以我认为虚拟参数解决方法在这里不是正确的解决方案——但如果我弄错了,请告诉我,并且在 C++17 中仍然存在限制。
不能在命名空间范围内声明模板成员的专用化成员。
若要避免此限制,可以使用 c++14 及更早版本以前需要的解决方法,其中包括使用部分专用化而不是完全专用化:
template <typename Outer>
struct ContainingClass {
template <typename T,class=void>
struct Rule {
Rule(T value);
// ... other members ...
};
template <class U>
struct Rule<void,U> {
Rule();
// ... different members than the non-void Rule<T> ...
};
};
template <typename Outer>
template <typename T, typename U>
ContainingClass<Outer>::Rule<T,U>::Rule(T value) { }
template <typename Outer>
template <typename U>
ContainingClass<Outer>::Rule<void,U>::Rule() { }
在 C++17 中,仍然无法在命名空间范围内声明类模板的专用化成员(成员),请参阅 [temp.expl.spec]/17。C++14标准中也存在相同的段落。
C++17 的变化是,我们可以在封闭类模板定义中声明成员的专用化:
- C++14/[templ.expl.spec]/2
应在包含专用模板的命名空间中声明显式专用化。...]
- C++17/[templ.expl.spec]/2
可以在可以定义相应主模板的任何范围内声明显式专用化。...]
- 具有专用化的模板类中的可靠条件复制和移动构造函数
- 构造函数 (g++) 的显式模板专用化
- 构造函数的部分模板专用化
- 如何在另一个类模板中定义完全专用类的构造函数
- 模板专用类之间的构造函数重载
- 使用模板的构造函数专用化
- 如何将模板构造函数专用化移动到 cpp 文件
- 模板类模板构造函数专用化
- 定义专用模板类构造函数时避免重复
- 模板化类的模板化构造函数的显式模板专用化
- 具有 n 个参数的模板专用构造函数
- 不会调用模板化构造函数的专用模板
- 没有模板参数的类的C++专用构造函数(跳过尖括号)
- 专用于非模板类的模板化构造函数
- 专用于模板类构造函数
- C++单个构造函数模板专用化
- 模板专用化没有匹配的构造函数
- 在模板专用化中添加单个构造函数方法
- 从派生类实现基类构造函数专用化的替代方法是什么
- 类定义中构造函数的模板专用化