以下代码编译using both Clang and 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>();
}
它应该编译吗?
答案 0 :(得分:16)
Foo_t<T>::Bar
可能看起来像一个依赖名称,但它不是因为传递给 alias-declaration 的 template-arguments 不会被使用确定 qualified-id Bar
所指的内容。
代码格式正确。
14.5.7 / 2 别名模板
[temp.alias]
当 template-id 引用别名模板的特化时,它等同于关联的类型 通过将 template-arguments 替换为别名的 type-id 中的 template-parameters 获得 模板。
A.6 声明
[gram.dcl]
alias-declaration: using identifier attribute-specifier-seq_opt = type-id ;
由于Foo_t
的 type-id 中没有 template-parameters ,模板alias-declaration 始终是直接等同于Foo
,无论我们传递给它的 template-arguments 。
template<class... Ts>
using Foo_t = Foo;
// ^--- "Foo" = type-id
将Foo_t<T>
的用法替换为模板alias-declaration 的等价物,为我们留下以下内容:
template<class T>
void f(){
Foo::Bar b; // ok, nothing here depends on `T`
}
答案 1 :(得分:8)
进一步挖掘,这是CWG issue 1390。
问题描述是
根据14.6.2.1 [temp.dep.type]第8段,类型是依赖的 (除其他外)如果是
simple-template-id ,其中模板名称是模板 参数或任何模板参数是依赖类型或 表达式依赖于类型或依赖于值
这适用于别名模板特化,即使是结果 type不依赖于模板参数:
struct B { typedef int type; }; template<typename> using foo = B; template<typename T> void f() { foo<T>::type * x; //error: typename required }
对此类案件的规则进行更改是否有必要?
这个问题有一个注释:
2012年10月会议的说明:
CWG同意在这种情况下不需要
typename
。在一些 方式,别名模板专业化就像当前一样 实例化,可以在模板定义时知道。
问题仍处于“起草”状态,但看起来编译器供应商已经在实施预期的解决方案。