在C中,需要 typename
关键字,因此编译器可以消除模板中嵌套类型和嵌套值之间的歧义 . 但是,在某些情况下,不存在歧义,例如派生类继承嵌套类类型时 .
template <class T>
class Derived : public T::type
{ };
这里不需要 typename
关键字,实际上甚至不允许 . 这是有道理的,因为上下文消除了歧义 . 这里, T::type
必须引用一个类型,因为你显然不能从一个值继承 .
我认为同样的事情适用于函数模板参数 .
template <class T>
void foo(const T::type& v)
{
}
在这种情况下,上下文清楚地表明 T::type
必须引用一个类型,因为函数参数可以't be a value. Yet, the compiler doesn' t接受它 . 它想要 const typename T::type&
. 这似乎不一致 . 为什么语言允许在继承的上下文中隐式假设嵌套类型,而不是在函数参数的上下文中?在这两种情况下都不会有歧义,为什么需要 typename
在一个而不是另一个?
3 回答
如果你稍微改变你的声明,你会得到一个完全不同的故事
这不再是明确的 . 它可以声明一个
void
类型的变量,该变量由逐位AND
表达式初始化 . 整个声明都是模板化的 . 当然,这在语义上都是无稽之谈,但从语法上来说还是不错的 .单个
const
在语法上的外观使其明确无误,但是在编译器中使这个工作有太多的上下文依赖性 . 它必须记住它读取const
或任何其他类似的东西,当它解析T::type
后,它需要记住将此名称作为一种类型 . 它还会使已经很复杂的标准进一步膨胀 .让我们再次更改您的函数声明
甚至在那里
const
的外观都没有提供明确的解析 . 它应该是一个带有未命名参数的函数声明,还是一个带有无效参数名称的函数声明而错过了它的类型?参数的名称由declarator-id
解析,也可以是限定名称 . 所以这里,const
将属于类型说明符,而T::type
将被编译器解析为参数的名称,没有typename
. 这完全是胡说八道,but is syntactically valid .在基类名称的情况下,名称查找本身表明忽略了非类型名称 . 因此,您可以免费省略
typename
:名称查找产生的名称对编译器的更高级别模块引用的类型或名称查找将给出错误 .我写了一篇关于Where to put the "template" and "typename" on dependent names的FAQ条目 .
首先,我认为没有意图在仅允许类型名称的情况(如基类名称)和允许非类型实体的情况(如表达式)之间做出明确而精确的区分 . 我会说由于其他原因,基类名称上下文被挑出来了 .
其次,在函数参数声明中说每个实体都必须是一个类型名称并不完全正确 . 您可以按如下方式声明参数
当然,这种情况下的语法明确规定
type
必须是一个类型名称,value
必须是一个值 . 但是,编译器只能在声明的句法分析之后才能解决这个问题,而我认为引入typename
的想法是为了帮助编译器实际开始对代码进行适当的语法分析,即在语法之前应该有区别 . 分析,作为句法分析的输入 . 这种区别可能会对代码的解释产生深远的影响 .找到造成这种情况的原因会很有趣 .
我一直试图阅读标准以寻找答案,请注意我是新手 .
不过,我相信我已找到相关条款 .
我想这意味着问题在于名称查找如何适用于基本说明符列表和函数参数 .
基本说明符名称查找:
这解释了为什么基本说明符不需要 typename .
仍在寻找函数参数名称查找 .
如果这是一个不正确或不相关的假设,请纠正我 . 与此同时,我一直在挖掘 .
VS2010在不对函数声明中的模板参数进行限定时给出的错误如下:
但是,我仍然不清楚依赖函数参数名称查找的规则...