c++ - 带有模板模板参数的 CRTP

标签 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> {
        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/

相关文章:

c++ - 'using'指令如何与模板成员函数一起工作

c++ - 使用派生类型的C++ Mixin

c++ - 指针和 QVector 问题

c++ - 为什么 std::function 不是有效的模板参数,而函数指针是?

javascript - 从 lodash 和 lodash/template 导入模板的区别?

c++ - 模板函数中的局部结构

c++ - 是否可以在 C++ 中序列化和反序列化一个类?

c++ - QwebEnginePage不打印html代码Qt

c++ - 声明类的 C 函数友元并返回 C 枚举器

c++ - CRTP 的替代品