Шаблоны '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>();
}
Должен ли он компилироваться?
Ответы
Ответ 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
. В некоторых способов, специализация шаблона псевдонима похожа на текущую экземпляр и может быть известен во время определения шаблона.
Проблема все еще находится в статусе "составления", но похоже, что поставщики компилятора уже реализуют предполагаемое разрешение.