【问题标题】:Clang and Intel fail to compile this CRTP codeClang 和 Intel 无法编译此 CRTP 代码
【发布时间】:2012-12-22 10:19:06
【问题描述】:

我编写了一个使用大量 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,你觉得以后的版本会解决吗?

【问题讨论】:

  • 这是一个很好的问题,但通常 CRTP 不会打扰模板模板参数,而只是让 Derived 类传递类型。 template&lt;typename Derived&gt; struct Base; template&lt;typename T&gt; struct Derived: Base&lt; Derived&lt;T&gt; &gt; { ... }; 比较正常。
  • ...如果您想传播Type,也许您可​​以在Derived 中有一个typedef 来暴露它...
  • 标识符Derived 在其自己的类中命名为完整类型Derived&lt;Whatever&gt;。这称为 injected 类名。我认为这是 GCC 的一个错误。
  • + 好问题,我也想看到一个明确的答案
  • @Xeo :有没有办法在类中获取非完整类型?

标签: c++ templates c++11 compiler-errors crtp


【解决方案1】:

在类Derived 中,名称Derived 指的是(实例化的)类,而不是类模板。请改用Base&lt; ::Derived, Type&gt;(注意在

【讨论】:

  • 注意:空格的原因是&lt;:可以解释为digraph,因此&lt;::在预处理后会被视为[:...
  • 在 C++11 中,你可以只写&lt;::Derived&lt;: 不会被解释为模板参数列表中的二合字母。
  • @MatthieuM。另请注意,这仅适用于 C++11(或 GCC
  • @Xeo:谢谢!我偶然发现了几次,真是令人沮丧:(
  • 我从来没有使用过这种语法,所以你能描述一下“::”在这种情况下的确切含义吗(或发布一个教程/解释的链接)。
【解决方案2】:

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

类模板也注入了类名。然而,他们 比普通注入的类名更陌生:可以跟在后面 模板参数(在这种情况下,它们被注入类模板 名称),但如果它们后面没有模板参数,它们 用参数作为参数表示类(或者,对于 部分特化,它的特化参数)。这说明 以下情况:

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&lt;Derived, Type&gt; 被解释为格式错误的 Base&lt;Derived&lt;Type&gt;, Type&gt;。因此,您需要使用范围限定符 ::,并在 &lt; 之间添加一个空格以避免有向图。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-25
    • 1970-01-01
    • 2012-04-01
    • 2020-12-19
    • 2020-08-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多