'typename'和别名模板

'typename' and alias templates

本文关键字:typename 别名      更新时间:2023-10-16

以下代码同时使用 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>();
}

它应该编译吗?

简介

Foo_t<T>::Bar可能看起来像一个依赖名称,但事实并非如此,因为在确定限定 id Bar引用的内容时,不会使用传递给别名声明模板参数

代码格式正确。



标准 (N3337) 怎么说?

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

当模板 id 引用别名模板的专用化时,它等效于关联的类型 通过将其模板参数替换为别名的类型 ID 中的模板参数获得 模板。

A.6 声明 [gram.dcl]

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


标准到底在说什么?

由于 Foo_t 的类型 id 中没有模板参数,模板别名声明总是直接等价于 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`
}

再深入挖掘一下,这就是CWG问题1390。

问题描述为

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

简单模板 ID,其中模板名称为模板 参数或任何模板参数是依赖类型或 与类型相关或值相关的表达式

这适用于别名模板专用化,即使生成的 类型不依赖于模板参数:

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。在一些 方式,别名模板专用化就像当前的 实例化,并且可以在模板定义时知道。

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