Подтвердить что ты не робот

Clang и Intel не могут скомпилировать этот CRTP-код

Я написал небольшую библиотеку, которая использует много методов метапрограммирования С++ 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, вы думаете, что он будет решен в будущей версии?

4b9b3361

Ответ 1

Внутри класса Derived имя Derived относится к классу (экземпляр), а не к шаблону класса. Вместо этого попробуйте Base< ::Derived, Type> (будьте осторожны, чтобы оставить пробел между < и::).

Ответ 2

В разделе 9.2.3 шаблона С++ полное руководство (Amazon), есть обсуждение Injected Имена классов. Цитировать:

В шаблонах классов также введены имена классов. Однако они более странные, чем обычные имена впрыснутых классов: за ними могут последовать аргументы шаблона (в этом случае они вводятся шаблон класса имена), но если за ними не следуют аргументы шаблона, они представляют класс со своими параметрами в качестве своих аргументов (или для частичная специализация, аргументы специализации). Это объясняет следующая ситуация:

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>, который плохо сформирован. Поэтому вам нужно использовать квалификатор области :: с пробелом между <, чтобы избежать орграфа.