Tl; dr:解决该问题的最便携和最不广泛的方法似乎是::Derived
在您的示例中使用限定名称:
template<typename T>
struct Derived : Base<T, Derived>
{
Derived(const T& _t) : Base<T, ::Derived>(_t) { }
};
为什么?
问题是编译器不符合 C++11。
像普通(非模板)类一样,类模板有一个注入类名(第 9 条)。注入的类名可以用作模板名或类型名。当它与模板参数列表一起使用时,作为模板模板参数的模板参数,或作为朋友类模板声明的详细类型说明符中的最终标识符,它指的是类模板本身。
因此,您的代码应该可以编译,但不幸的是,我测试的所有编译器(clang 3.7、Visual Studio 2015 和 g++5.3)都拒绝编译。
Afaik,您应该能够在Derived
定义中以各种方式表示模板:
- 直接使用注入的名称
Derived
- 类模板的限定名称
::Derived
- 使用注入的类名,将其指定为模板名
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 | + | + | + |
+---------------------------------+----------+---------+-----------+