Ответ 1
Внутри класса Derived
имя Derived
относится к классу (экземпляр), а не к шаблону класса. Вместо этого попробуйте Base< ::Derived, Type>
(будьте осторожны, чтобы оставить пробел между < и::).
Я написал небольшую библиотеку, которая использует много методов метапрограммирования С++ 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 шаблона С++ полное руководство (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>
, который плохо сформирован. Поэтому вам нужно использовать квалификатор области ::
с пробелом между <
, чтобы избежать орграфа.