Подтвердить что ты не робот

Шаблоны 'typename' и alias

Следующий код компилирует с использованием как Clang, так и GCC, хотя Foo_t<T>::Bar не имеет typename перед ним:

struct Foo {
    using Bar = int;
};

template<class...>
using Foo_t = Foo;

template<class T>
void f(){
    Foo_t<T>::Bar b; // No typename!
}

int main(){
    f<int>();
}

Должен ли он компилироваться?

4b9b3361

Ответ 1

Введение

Foo_t<T>::Bar может выглядеть как зависимое имя, но это не так, поскольку аргументы шаблона, переданные объявлению alias, не используются при определении того, к чему относится квалифицированный идентификатор Bar.

Код корректно сформирован.



Что означает стандарт (N3337)?

14.5.7/2 Шаблоны псевдонимов [temp.alias]

Когда идентификатор шаблона ссылается на специализацию шаблона псевдонима, он эквивалентен связанному типу   полученный путем подстановки его шаблонов-аргументов для параметров шаблона в идентификаторе типа псевдонима   шаблон.

A.6 Объявления [gram.dcl]

alias-declaration:
  using identifier attribute-specifier-seq_opt = type-id ;


Что действительно означает "Стандарт"?

Поскольку в идентификаторе типа Foo_t нет шаблонных параметров, объявление шаблона шаблона всегда будет непосредственно эквивалентно Foo, независимо от того, какие шаблонные аргументы мы передаем ему.

template<class... Ts>
using Foo_t = Foo;
//            ^--- "Foo" = type-id

Замена использования Foo_t<T> на эквивалентность объявления псевдонима шаблона оставляет нам следующее:

template<class T>
void f(){
    Foo::Bar b; // ok, nothing here depends on `T`
}

Ответ 2

С еще одним копанием это CWG issue 1390.

Описание проблемы

Согласно пункту 14.6.2.1 [temp.dep.type], тип зависит от (между прочим), если это

простой шаблон-идентификатор, в котором либо имя шаблона является шаблоном   параметр или любой из аргументов шаблона является зависимым типом или   выражение, зависящее от типа или зависящее от стоимости

Это относится к специализациям шаблонов псевдонимов, даже если результат тип не зависит от аргумента шаблона:

struct B { typedef int type; };
template<typename> using foo = B;
template<typename T> void f() {
  foo<T>::type * x;  //error: typename required
}

Является ли изменение правил для таких случаев, как это гарантировано?

И в этом выпуске есть заметка:

Заметки из собрания в октябре 2012 года:

CWG согласилась, что в этом случае не требуется typename. В некоторых способов, специализация шаблона псевдонима похожа на текущую экземпляр и может быть известен во время определения шаблона.

Проблема все еще находится в статусе "составления", но похоже, что поставщики компилятора уже реализуют предполагаемое разрешение.