C++ 带有模板参数的CRTP
以下代码未编译C++ 带有模板参数的CRTP,c++,templates,crtp,template-templates,C++,Templates,Crtp,Template Templates,以下代码未编译 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> {
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;
}
名称空间{
模板
结构基{
基(常数T&_T):T(_T){
T;
};
模板
派生结构:基{
派生(常量T&_T):基(_T){
};
}
int main(int argc,char*argv[]){
导出d(1);
返回0;
}
第-Derived(const T&\u T):Base(\u T){}
错误C3200“`匿名命名空间'::派生”:模板无效
模板参数“D”的参数,应为类模板
如果我提供了任何其他具有模板参数而不是派生自身的类,那么这是可行的
template<typename T>
struct Other {
};
template<typename T>
struct Derived : Base<T, Other> {
Derived(const T& _t) : Base<T, Other>(_t) { }
};
模板
结构其他{
};
模板
派生结构:基{
派生(常量T&_T):基(_T){
};
在类模板中,注入的类名(在您的示例中派生的
)可以是类型名和模板名。该标准规定,当将其用作模板参数的参数时,应考虑将其命名为模板(因此代码应该可以工作),但遗憾的是,一些编译器尚未实现这一点
一种解决方法是使用限定名称,这样您就不用注入的类名,而是直接命名模板:
template<typename T>
struct Derived : Base<T, Derived> {
Derived(const T& _t) : Base<T, ::Derived>(_t) { }
};
模板
派生结构:基{
派生(常量T&_T):基(_T){
};
Tl;dr:解决这个问题的最方便和最不广泛的方法似乎是使用限定名称::Derived
,在您的示例中:
template<typename T>
struct Derived : Base<T, Derived>
{
Derived(const T& _t) : Base<T, ::Derived>(_t) { }
};
将名称空间命名为X
时,图片会发生一些变化(即g++
现在接受X::template-Derived
,而拒绝::template-Derived
):
+---------------------------------+----------+---------+-----------+
|方法| MSVS2015 | g++5.3 | clang 3.7|
+---------------------------------+----------+---------+-----------+
|派生的|-|-|-|
|X::派生的|+|+|+|
|X::派生::模板派生|-|-|+|
|X::模板派生的|+|+|+|
+---------------------------------+----------+---------+-----------+
原因是Base
的D
需要一个模板。在Derived
内部,名称Derived
是Derived
的注入实例(即在您的案例中为Derived
),它不是模板,而是具体类型。可能与“某些编译器”重复哪个?@PiotrSkotnicki你认为它应该始终是一个模板名,不能用作类型名?@PiotrSkotnicki:正确<代码>注入类名称的声明点(第9条)紧跟在类定义的左括号之后。@PiotrSkotnicki-Oh,右,在基说明符中。你是对的-每个人都认为一个是模板名。已修复。通过Derived::template-Derived
使用注入名称表示类模板使用clang 3.7编译,但被MSVC 2015和g++5.3拒绝。
+------------------------------+----------+---------+-----------+
| Method | MSVS2015 | g++ 5.3 | clang 3.7 |
+------------------------------+----------+---------+-----------+
| Derived | - | - | - |
| ::Derived | + | + | + |
| Derived<T>::template Derived | - | - | + |
| ::template Derived | + | - | + |
+------------------------------+----------+---------+-----------+
+---------------------------------+----------+---------+-----------+
| Method | MSVS2015 | g++ 5.3 | clang 3.7 |
+---------------------------------+----------+---------+-----------+
| Derived | - | - | - |
| X::Derived | + | + | + |
| X::Derived<T>::template Derived | - | - | + |
| X::template Derived | + | + | + |
+---------------------------------+----------+---------+-----------+