将typename关键字与模板函数参数一起使用

Cha*_*l72 28 c++ templates typename

在C++中,typename需要关键字,因此编译器可以消除模板中嵌套类型和嵌套值之间的歧义.但是,在某些情况下,不存在歧义,例如派生类继承嵌套类类型时.

template <class T>
class Derived : public T::type
{ };
Run Code Online (Sandbox Code Playgroud)

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

我认为同样的事情适用于函数模板参数.

template <class T>
void foo(const T::type& v)
{

}
Run Code Online (Sandbox Code Playgroud)

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

Joh*_*itb 23

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

template <class T>
void foo(T::type& v);
Run Code Online (Sandbox Code Playgroud)

这不再是明确的.它可以声明一个void由逐位AND表达式初始化的类型变量.整个声明都是模板化的.当然,这在语义上都是无稽之谈,但从语法上来说还是不错的.

单个const语法的出现使其明确无误,但是在编译器中使这个工作有太多的上下文依赖性.它必须记住它读取一个const或任何其他这样的东西,当它解析T::type后,它将需要记住将此名称作为一种类型.它还会使已经复杂的标准进一步膨胀,超出信念.

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

template <class T>
void foo(const T::type);
Run Code Online (Sandbox Code Playgroud)

甚至const在那里的外观都没有提供明确的解析.它应该是一个带有未命名参数的函数声明,还是一个带有无效参数名称的函数声明而错过了它的类型?参数的名称由a解析declarator-id,也可以是限定名称.所以在这里,constwill将属于类型说明符,而T::type编译器将解析它作为参数的名称,如果没有typename.这完全是胡说八道,但在语法上是有效的.

在基类名称的情况下,名称查找本身表明忽略了非类型名称.所以你得到typename免费的遗漏:名称查找产生更高级别的编译模块的名称要么是一个类型,要么名称查找会给出错误.

我写了一个FAQ条目,关于在依赖名称上放置"模板"和"typename"的位置.

  • 我不知道我是否应该敬畏发现这些案件,或者真的害怕你的理智:) (3认同)

AnT*_*AnT 5

首先,我认为从来没有意图在只允许类型名称(如基类名称)的情况和也允许非类型实体(如表达式)的情况之间进行明确区分。我想说,基类名称上下文是出于其他原因而被挑选出来的。

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

template <class T>
void foo(const T::type& v[T::value]);
Run Code Online (Sandbox Code Playgroud)

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