Текущие компиляторы C ++ (последние gcc, clang) требуют typename
Ключевое слово в примере ниже:
template<class T>
struct A
{
};
template<class T>
void f(T)
{
struct C
{
};
typedef typename A<C>::Type Type; // typename required
}
Если typename
опущен gcc (4.9, 5.0) сообщает об ошибке:
need 'typename' before 'A<f(T)::C>::Type' because 'A<f(T)::C>' is a dependent scope
Этот пример хорошо сформирован в соответствии с моим прочтением стандарта C ++ 11.
Такое поведение, по-видимому, охватывается следующей формулировкой:
[Temp.dep.type] / 8Тип зависит, если он
параметр шаблона,
член неизвестной специализации,
вложенный класс или перечисление, являющееся членом текущего экземпляра,
cv-квалифицированный тип, где cv-неквалифицированный тип является зависимым,
составной тип, построенный из любого зависимого типа,
тип массива, созданный из любого зависимого типа или размер которого определяется константным выражением
это зависит от стоимости,простой-шаблон-идентификатор, в котором либо имя шаблона является параметром шаблона, либо любым из шаблона
arguments является зависимым типом или выражением, которое зависит от типа или значения, илиобозначается decltype (выражение), где выражение зависит от типа.
Тем не менее, в соответствии с [class.local] класс C
это местный класс, а не вложенными учебный класс. Если так, то почему A<C>
лечиться как зависимый?
РЕДАКТИРОВАТЬ
Для бонусных баллов, если пример изменен путем добавления перечисления члена в C
следующее:
template<typename T>
struct A
{
typedef T Type;
};
template<class T>
void f(T)
{
struct C
{
enum { value = T::value };
};
typedef typename A<C>::Type Type; // typename required
}
Должен A<C>
теперь относиться как к зависимым?
Согласно моему пониманию (и нынешней редакции стандарта), C
в вашем примере это не зависит. Ни то, ни другое A<C>::Type
, Итак typename
не требуется.
Существует фундаментальное различие между вложенными классами шаблонов классов и локальными классами в шаблонах функций: последние не могут быть специализированными, поэтому любая ссылка на локальный класс внутри шаблона функции является однородной. То есть в каждой специализации f
, C
относится к классу C
что определено в этом шаблоне функции f
, Это не относится к шаблонам классов, поскольку вы действительно можете явно специализировать членов самостоятельно (как описано в [temp.expl.spec]
/(1.6)):
template <typename T>
class A { class C{}; };
template <>
class A<int>::C { int i; };
Тем не мение:
Тип зависит, если он
- составной тип, построенный из любого зависимого типа,
Так что, если определение было сделано как в пример дипа, C
будет зависеть от того, как он построен из T
,
Существуют неясности в формулировке стандартов, которые обсуждаются в разделе комментариев, например об определениях функций-членов, которые зависят от T
и как это переносится на зависимость классов.
Следующее — мои рассуждения, надеюсь, это поможет. Местный C
не создается до f
экземпляр. Так, A<C>
не является экземпляром и непрозрачен для компилятора, когда он его видит. Из-за непрозрачности компилятор не может определить, A<C>::Type
является именем вложенного типа или членом данных или методом. Однако по умолчанию компилятор не видит A<C>::Type
как имя вложенного типа. Следовательно, необходима явная спецификация.
Похоже, в стандарте нет ничего, чтобы утверждать, что typename
ключевое слово должно быть необходимо здесь. Формулировка также явно не указывает на иное, что, возможно, привело к тому, что GCC предпринял небольшой шаг в лечении f<T>(T)::C
(будучи локальным классом в специализации шаблона функции) в зависимости от T
— по расширению, это сделало бы A<[f<T>(T)::]C>::Type
зависимый.
Основной дефект 1484 не был поднят конкретно по этому вопросу, но я думаю, что дополнительный ненормативный текст, который он предлагает, проясняет намерение, и, будь это в стандарте, GCC не будет требовать typename
Ключевое слово здесь.