Я написал небольшую библиотеку, в которой используется множество методов метапрограммирования 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, думаете ли вы, что это будет решено в будущей версии?
Внутри класса Derived
, имя Derived
ссылается на (созданный экземпляр) класс, а не на шаблон класса. Пытаться Base< ::Derived, Type>
вместо этого (будьте осторожны, чтобы оставить пространство между < а также ::).
В разделе 9.2.3 Шаблон C ++ Полное руководство (Амазонка), есть обсуждение Имен введенных классов. Цитировать:
Шаблоны классов также имеют введенные имена классов. Тем не менее, они
незнакомые, чем обычные введенные имена классов: за ними могут следовать
аргументы шаблона (в этом случае в них вводится шаблон класса
имена), но если они не сопровождаются аргументами шаблона, они
представлять класс с его параметрами в качестве аргументов (или, для
частичная специализация, аргументы ее специализации). Это объясняет
следующая ситуация:
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>
который плохо сформирован. Поэтому вам нужно использовать квалификатор области ::
с пробелом между <
избегать орграфа.