2013-07-16 2 views
19

Я получаю ошибки компиляции при попытке вызвать конструктор базового класса в производном списке инициализации при использовании параметра шаблона шаблона с помощью CRTP.clang ++ не принимает использование параметра шаблона шаблона при использовании CRTP

Проблема может быть воспроизведен с этим фрагментом кода:

template <template<class> class Derived, class T> 
struct base 
{ 
}; 

template <class T> 
struct derived : public base<derived, T> 
{ 
    derived() 
     : base<derived, T>() 
    { } 
}; 

messsage ошибка обижая:

bug.cpp:10:16: error: template argument for template template parameter must be a class template or type alias template 
     : base<derived, T>() 
      ^
bug.cpp:10:11: error: expected class member or base class name 
     : base<derived, T>() 
     ^
bug.cpp:10:11: error: expected '{' or ',' 
3 errors generated. 

Эта проблема появляется только произойдет на лязгом (3.4), а не g ++ (4.8, 4.7, 4.6). Я также компилирую с -std = C++ 11.

Это первый раз, когда мне нужно было использовать CRTP с параметром шаблона шаблона. Я делаю это хорошо, и это проблема с clang ++ или нет?

Я вырос, чтобы доверять clang ++ сообщения об ошибках больше, чем g ++ в последнее время!

ответ

17

Ваш код является законным.

С 11 C++ Standard, раздел 14.6.1:

Как и обычные (не шаблон) классов, шаблоны классов имеют впрыскивается-имя-класса (пункт 9). Имя введенного класса может использоваться как имя шаблона или имя типа. Когда используется с шаблоном-аргументом-списком, в качестве шаблона-аргумента для шаблона-шаблона шаблона или в качестве окончательного идентификатора в специфицированном типе описания объявления шаблона класса друга, , он ссылается к самому шаблону класса.

Похоже, что ваша версия clang по-прежнему реализует старое правило. Исходя из ваших дополнительных комментариев, это может быть сделано только в ctor-initializer-list.


Пользователь David Rodríguez - dribeas предоставил обходной путь для компиляторов, которые не в полной мере реализованы на C++ 11 правила нагнетаемого имени-класса. Используйте любое имя класса, который не является безоговорочным, например:

derived() 
    : base< ::derived, T >() 
//   ^^ qualified with global namespace 
{ } 

Некоторые компиляторы могут требовать этого в списке наследования также:

template <class T> 
struct derived : public base< ::derived, T > 
//       ^^ 
+0

+1 Не знаю, что это изменилось в C++ 11. Возможно, вы захотите предоставить обходной путь, который был у меня в удаленном ответе. –

+0

@ DavidRodríguez-dribeas: не стоит беспокоиться, новый стандарт все еще меня удивляет. –

+1

Я не волнуюсь, наоборот, я чему-то научился. Я был бы взволнован в тот день, когда не узнаю ничего нового :) –

Смежные вопросы