以下代码无法编译...
namespace {
template<typename T, template<typename> class D>
struct Base {
Base(const T& _t) : t(_t) { }
T t;
};
template<typename T>
struct Derived : Base<T, Derived> {
Derived(const T& _t) : Base<T, Derived>(_t) { }
};
}
int main(int argc, char* argv[]) {
Derived<int> d(1);
return 0;
}
行有编译错误 - Derived(const T& _t) : Base<T, Derived>(_t) { }
Error C3200 '`anonymous-namespace'::Derived': invalid template argument for template parameter 'D', expected a class template
如果我提供任何其他具有模板参数而不是 Derived 本身的类,则此方法有效
template<typename T>
struct Other {
};
template<typename T>
struct Derived : Base<T, Other> {
Derived(const T& _t) : Base<T, Other>(_t) { }
};
最佳答案
Tl;dr:解决这个问题的最便携和最不广泛的方法似乎是使用限定名称 ::Derived
在你的例子中:
template<typename T>
struct Derived : Base<T, Derived>
{
Derived(const T& _t) : Base<T, ::Derived>(_t) { }
};
为什么?
问题是编译器不符合 C++11。
Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-typespecifier of a friend class template declaration, it refers to the class template itself.
因此您的代码应该可以编译,但不幸的是,我测试的所有编译器(clang 3.7、Visual Studio 2015 和 g++5.3)都拒绝编译。
Afaik,您应该能够在 Derived
内以各种方式表示模板定义:
- 直接使用注入(inject)的名称
Derived
- 类模板的限定名
::Derived
- 使用注入(inject)的类名,指定为模板名
Derived<T>::template Derived
- 使用限定名称,再次将其指定为模板名称
::template Derived
那些编译器关于这四个选项的编译状态如下(使用匿名命名空间;其中+
= 编译成功):
+------------------------------+----------+---------+-----------+
| Method | MSVS2015 | g++ 5.3 | clang 3.7 |
+------------------------------+----------+---------+-----------+
| Derived | - | - | - |
| ::Derived | + | + | + |
| Derived<T>::template Derived | - | - | + |
| ::template Derived | + | - | + |
+------------------------------+----------+---------+-----------+
给命名空间命名时 X
,图片略有变化(即 g++
现在接受 X::template Derived
而拒绝 ::template Derived
):
+---------------------------------+----------+---------+-----------+
| Method | MSVS2015 | g++ 5.3 | clang 3.7 |
+---------------------------------+----------+---------+-----------+
| Derived | - | - | - |
| X::Derived | + | + | + |
| X::Derived<T>::template Derived | - | - | + |
| X::template Derived | + | + | + |
+---------------------------------+----------+---------+-----------+
关于c++ - 带有模板模板参数的 CRTP,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34739555/