Ответ 1
Во-первых:
[C++11: 12.6.2/3]:
Список mem-initializer может инициализировать базовый класс, используя любой класс или-decltype, который обозначает этот тип базового класса.[Пример:
struct A { A(); }; typedef A global_A; struct B { }; struct C: public A, public B { C(); }; C::C(): global_A() { } // mem-initializer for base A
-end пример]
И Base
должен быть допустимым именем впрыскиваемого класса для базы здесь (т.е. вы можете использовать его вместо Base<T>
):
[C++11: 14.6.1/1]:
Подобно обычным (не шаблонным) классам, шаблоны классов имеют имя с введенным классом (раздел 9). Имя введенного класса может использоваться как имя шаблона или имя типа.. Когда он используется с шаблоном-аргументом-списком, в качестве шаблона-аргумента для шаблона-шаблона шаблона или как конечный идентификатор в спецификаторе разработанного типа объявления шаблона класса друга, оно относится к самому шаблону класса. В противном случае он эквивалентен имени шаблона, за которым следуют шаблонные параметры шаблона класса, заключенного в<>
.
[C++11: 14.6.1/3]:
Введенное имя класса шаблона класса или специализации шаблона шаблона можно использовать либо как имя шаблона, либо имя типа везде, где оно находится в области видимости. [Пример:template <class T> struct Base { Base* p; }; template <class T> struct Derived: public Base<T> { typename Derived::Base* p; // meaning Derived::Base<T> }; template<class T, template<class> class U = T::template Base> struct Third { }; Third<Base<int> > t; // OK: default argument uses injected-class-name as a template
-end пример]
Я не нашел ничего, чтобы указать, что это не применяется в ctor-initializer, поэтому я бы сказал, что это ошибка компилятора.
Мой усеченный тестовый файл не работает в GCC 4.1.2 и GCC 4.3.4, но преуспевает в GCC 4.5.1 (режим С++ 11). Кажется, это разрешено ошибка GCC 189; в примечания к выпуску GCC 4.5:
g++ теперь реализует DR 176. Ранее g++ не поддерживал использование inted-class-name базового класса шаблона в качестве имени типа и поиск имени нашел объявление шаблона в охватывающий объем. Теперь поиск имени находит имя впрыснутого класса, которые могут использоваться либо как тип, либо как шаблон, в зависимости от следует ли за ним следовать список аргументов шаблона. Как результат этого изменения, некоторый код, который был ранее принят, может быть плохо сформирован, потому что
- Имя введенного класса недоступно, потому что оно из частной базы или
- Введенное имя класса не может использоваться в качестве аргумента для параметра шаблона шаблона.
В любом из этих случаев код может быть исправлен путем добавления inested-name-specifier, чтобы явно указать шаблон. Первый может работать с -fno-access-control; второй отклоняется с -pedantic.
Мой усеченный тестовый диск с Qt абстрагированным:
template <typename T>
struct Base { };
struct Derived : Base<Derived> { // I love the smell of CRTP in the morning
Derived();
};
Derived::Derived() : Base() {};