关于c ++:将typename关键字与模板函数参数一起使用

Use of typename keyword with template function parameters

在C++中,需要EDCOX1×0个关键字,这样编译器就可以在模板中嵌套类型和嵌套值之间消除歧义。但是,在某些情况下不可能有歧义,例如派生类从嵌套类类型继承时。

1
2
3
template <class T>
class Derived : public T::type
{ };

这里不需要typename关键字,实际上甚至不允许使用。这是有意义的,因为上下文消除了歧义。这里,T::type必须引用类型,因为显然不能从值继承。

我认为对于函数模板参数同样适用。

1
2
3
4
5
template <class T>
void foo(const T::type& v)
{

}

在这种情况下,上下文明确说明T::type必须引用类型,因为函数参数不能是值。然而,编译器不接受这一点。它想要const typename T::type&。这似乎不一致。为什么语言允许在继承上下文中而不是在函数参数上下文中隐式假设嵌套类型?在这两种情况下都不会有歧义,那么为什么一种情况下需要typename,而另一种情况下不需要呢?


如果你稍微改变你的声明,你会得到一个完全不同的故事

1
2
template <class T>
void foo(T::type& v);

这已经不含糊了。它可以声明一个类型为void的变量,该变量由位的AND表达式初始化。整个声明将被模板化。当然,从语义上讲,这完全是胡说八道,但从语法上讲,这是可以的。

单个const的出现在语法上使其明确,但它太依赖上下文,无法在编译器中工作。它必须记住它读一个const或任何其他类似的东西,当它解析T::type之后,它需要记住把这个名字作为一个类型。它还将进一步膨胀已经非常复杂的标准。

让我们再次更改您的函数声明

1
2
template <class T>
void foo(const T::type);

即使在这里出现了const,也没有提供明确的解析。它应该是带有未命名参数的函数声明,还是应该是带有未命中其类型的无效参数名的函数声明?参数的名称由declarator-id解析,它也可以是限定名。因此,在这里,const将属于类型说明符,而在没有typename的情况下,T::type将由编译器解析为参数名。这也完全是胡说八道,但在语法上是有效的。

在基类名称的情况下,名称查找本身声明将忽略非类型名称。因此,可以免费省略typename:名称查找产生的编译器更高级别模块的名称要么引用类型,要么名称查找会给出错误。

我写了一个关于将"模板"和"类型名"放在相关名称上的常见问题解答条目。


首先,我不认为有任何意图在只允许类型名的情况(如基类名)和允许非类型实体的情况(如表达式)之间作出尖锐而精确的区分。我想说的是,基类名上下文是由于其他原因而被挑选出来的。

其次,在函数参数声明中,每个实体都必须是一个类型名,这种说法并不完全正确。可以如下声明参数

1
2
template <class T>
void foo(const T::type& v[T::value]);

当然,本例中的语法明确规定type必须是一个类型名,value必须是一个值。然而,编译器只能在声明的句法分析之后才能理解,而我相信引入typename的思想是为了帮助编译器实际开始对代码进行正确的句法分析,即在句法分析之前应该有区别,作为句法分析的输入。这种区别可能对代码的解释产生深远的影响。


很有意思的发现是什么导致了这种情况。

我一直在尝试阅读标准来寻找答案,请注意,我是新手。

但是我相信我找到了一个相关的条款。

§14.6.2. A name used in a template
declaration or definition and that is
dependent on a template-parameter is
assumed not to name a type unless the
applicable name lookup finds a type
name or the name is qualified by the
keyword typename.

我想这意味着问题在于名称查找对于基本说明符列表和函数参数的工作方式的不同。

基本说明符名称查找:

§10.2. During the lookup for a base
class name, non-type names are ignored
(3.3.10).

这就解释了为什么基本说明符不需要类型名。

仍在查找函数参数名称查找。

如果这是一个不正确或不相关的假设,请纠正我。同时我一边挖一边挖。

在函数声明中不限定模板参数时,vs2010给出的错误如下:

'T::type' : dependent name is not a
type prefix with 'typename' to
indicate a type.

但是,我仍然不清楚依赖函数参数名称查找的规则…