'typename'和别名模板

T.C*_*.C. 24 c++ templates language-lawyer c++11

以下代码使用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>();
}
Run Code Online (Sandbox Code Playgroud)

它应该编译吗?

Fil*_*efp 16

介绍

Foo_t<T>::Bar可能看起来像一个依赖名称,但它不是因为在确定qualified-id引用的内容时不使用传递给alias-declarationtemplate-arguments. Bar

代码格式正确.



标准(N3337)说什么?

14.5.7/2 别名模板 [temp.alias]

模板id是指一个别名模板的专业化,它相当于通过其置换得到的相关联的类型的模板的参数模板参数类型ID别名模板.

A.6 声明 [gram.dcl]

alias-declaration:
  using identifier attribute-specifier-seq_opt = type-id ;
Run Code Online (Sandbox Code Playgroud)


标准真正说的是什么?

由于没有模板参数类型IDFoo_t,该模板别名声明总是直接等同于Foo,无论什么模板参数,我们传递给它.

template<class... Ts>
using Foo_t = Foo;
//            ^--- "Foo" = type-id
Run Code Online (Sandbox Code Playgroud)

Foo_t<T>模板别名声明的等价替换用法使我们得到以下内容:

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

  • @FilipRoséen-refp也许,但它也是*a*simple-template-id*,其中一个模板参数是一个依赖类型.因此,通过该子句,它*是一个依赖类型.在别名模板子句下,它也等同于`Foo`.`Foo`显然不是*依赖类型.从表面上看,这似乎是一个矛盾.是否有明确的条款规定必须解决这一矛盾,而不是依赖类型?或者"等价"是什么意思?或者[temp.dep.type]/p8中是否有一些子句规定"这不适用于此处"? (3认同)

T.C*_*.C. 9

通过更多挖掘,这是CWG问题1390.

问题描述是

根据14.6.2.1 [temp.dep.type]第8段,如果是,则类型依赖于(除其他外)

一个simple-template-id,其中模板名称是模板参数或任何模板参数是依赖类型或依赖于类型或依赖于值的表达式

这适用于别名模板特化,即使结果类型不依赖于模板参数:

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

这样的案件的规则是否有必要改变?

这个问题有一个注释:

2012年10月会议记录:

CWG同意typename在这种情况下不应该要求.在某些方面,别名模板特化与当前实例化类似,可以在模板定义时知道.

该问题仍然处于"起草"状态,但看起来编译器供应商已经在实现预期的解决方案.