11

我编写了一个使用大量 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)

那么它是 intel 和 clang 还是 g++ 中的错误?如果它在 intel 和 clang 中,你认为它会在未来的版本中解决吗?

4

2 回答 2

7

在 class 内部Derived,名称Derived指的是(实例化的)类,而不是类模板。请Base< ::Derived, Type>改用(注意在 < 和 :: 之间留一个空格)。

于 2013-01-08T14:42:57.613 回答
6

C++ Template the Complete Guide ( Amazon ) 的第 9.2.3 节中,有关于 Injected Class Names 的讨论。去引用:

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

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>格式错误的。因此,您需要使用范围限定符::,在 之间有一个空格<来避免有向图。

于 2013-01-08T16:03:35.787 回答