问题 Clang和Intel无法编译此CRTP代码


我编写了一个小型库,它使用了大量的C ++ 11元编程技术和CRTP,它与g ++ 4.7.2编译得很好。

现在,我尝试用Intel icpc 13.0.0.079编译它,它会产生数百个错误。所以我试着一个接一个地隔离问题。

所以,首先,考虑一下这个代码,它在g ++ 4.7.2下编译没有问题

#include <iostream>

template<template<typename> class Crtp, typename Type>
struct Base {};

template<typename Type>
struct Derived : public Base<Derived, Type>
{
    Derived(): Base<Derived, Type>() {;}
};

int main()
{
    Derived<int> x;
    return 0;
}

icpc和clang都无法编译此代码:

test_crtp.cpp(26): error: type "Derived<Type>::Derived" is not a class template
      Derived(): Base<Derived, Type>() {;}
                      ^

test_crtp.cpp(26): error: "Base" is not a nonstatic data member or base class of class "Derived<int>"
      Derived(): Base<Derived, Type>() {;}
                 ^
          detected during instantiation of "Derived<Type>::Derived() [with Type=int]" at line 31

compilation aborted for test_crtp.cpp (code 2)

那么它是英特尔和铿锵,还是用g ++中的错误?如果它是英特尔和铿锵的,你认为它将在未来的版本中得到解决吗?


11505
2018-01-08 14:26


起源

这是一个很好的问题,但通常CRTP不会打扰模板模板参数,只是让Derived类传递类型。 template<typename Derived> struct Base; template<typename T> struct Derived: Base< Derived<T> > { ... }; 更正常。 - Dave S
...如果你想传播 Type,也许你可以有一个 typedef 在 Derived 暴露它...... - Nim
标识符 Derived 名称,在其自己的类中,完整类型 Derived<Whatever>。这被称为 注射 班级名称。我认为这是GCC的一个错误。 - Xeo
+对于好问题,我也希望看到一个明确的答案
@Xeo:有没有办法在课堂上获得非完整类型? - Vincent


答案:


在课堂上 Derived, 名字 Derived 指的是(实例化的)类,而不是类模板。尝试 Base< ::Derived, Type> 相反(小心在<和::)之间留一个空格。


7
2018-01-08 14:42



注意:空间的原因是 <: 可以解释为 有向图, 因此 <:: 会被视为 [: 经过预处理...... - Matthieu M.
在C ++ 11中,你可以写 <::Derived, <: 不被解释为模板参数列表中的有向图。 - Xeo
@MatthieuM。另请注意,这仅适用于C ++ 11之前的C ++(或GCC <4.8)= - R. Martinho Fernandes
@Xeo:非常感谢!我偶然发现了几次,这真是令人沮丧:( - Matthieu M.
我从来没有使用过这种语法,所以在这种情况下你能描述一下“::”的确切含义(或者发一个教程的链接/解释它)。 - Vincent


在第9.2.3节中 C ++模板完整指南 (亚马逊),关于注入类名称的讨论。去引用:

类模板也有注入的类名。但是,他们是   比普通的注入类名更奇怪:它们可以跟着   模板参数(在这种情况下,它们是注入类模板   名称),但如果他们没有跟随模板参数   表示以其参数为参数的类(或者,对于a   部分专业化,其专业化论点)。这解释了   以下情况:

template<template<typename> class TT> 
class X {};

template<typename T> 
class C 
{
    Ca;        // OK: same as ''C<T> a;''
    C<void> b; // OK
    X<C> c;    // ERROR: C without a template argument list
               // does not denote a template
    X<::C> d;  // ERROR: <: is an alternative token for [
    X< ::C> e; // OK: the space between < and :: is required
}

请注意非限定名称如何引用注入的名称而不是   如果没有后面的列表,则考虑模板的名称   模板参数。为了弥补,我们可以强制命名   使用文件范围限定符::找到的模板。这有效,   但是我们必须小心不要创建一个所谓的有向图标记   <:,被解释为左括号。虽然比较少见,   这样的错误导致令人困惑的诊断。

那么你的代码会发生什么呢 Base<Derived, Type> 被解释为 Base<Derived<Type>, Type> 这是不正确的。因此,您需要使用范围限定符 :: 之间有空格 < 避免有图。


6
2018-01-08 16:03