Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 带有模板参数的CRTP_C++_Templates_Crtp_Template Templates - Fatal编程技术网

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             |    +     |    +    |     +     |
+---------------------------------+----------+---------+-----------+