struct A{};
template <typename T>
struct B
{
typename ::A a1; //(1)
typename A a2; //(2): error
};
int main(){return 0;}
为什么第一种情况正确,而第二种情况不正确?我不明白这个限制的含义。
无论如何,为什么允许第一种情况?::A
不是模板参数依赖名称。其中有什么意义?
struct A{};
template <typename T>
struct B
{
typename ::A a1; //(1)
typename A a2; //(2): error
};
int main(){return 0;}
为什么第一种情况正确,而第二种情况不正确?我不明白这个限制的含义。
无论如何,为什么允许第一种情况?::A
不是模板参数依赖名称。其中有什么意义?
该规则并不是您只能typename
在类型嵌套在依赖范围内时使用。规则或多或少是:
typename
如果它在依赖范围内,则必须使用typename
在语法允许的地方使用。语法允许它用于qualified-id的子集,由
typename-specifier:
typename nested-name-specifier identifier
typename nested-name-specifier template<opt> simple-template-id
nested-name-specifier:
:: (C++14 or later)
::<opt> type-name ::
::<opt> namespace-name ::
decltype-specifier ::
nested-name-specifier identifier ::
nested-name-specifier template<opt> simple-template-id ::
所以第二种情况肯定是被禁止的,因为它不涉及任何嵌套。严格来说,在 C++14 之前,第一个也是被禁止的,因为全局限定符::
与该语法不匹配。
正如@MikeSeymour 的回答所解释的那样,严格按照标准(C++11,我手头没有 C++14 文本),情况(1)实际上也应该是错误的 -typename
前缀限定名称只能是当 . 的左侧至少有一个名称时使用::
。
但是,正如@hvd 在评论中指出的那样,CWG 问题 382typename
表明实际意图是在任何限定名称之前允许,包括全局命名空间限定。由于这是大多数编译器似乎都实现的,所以这个答案的其余部分都遵循这个想法。
这样看,不是第(2)种是限制,而是第(1)种是仁。所需的规则(我相信它的原始措辞)基本上是“如果一个依赖于模板参数的限定名称表示一个类型,你必须在它前面加上typename
.”。为方便起见,它被放宽为“typename
可以用于任何限定类型的限定名称,无论它是否依赖。” (1)
相反,一个非限定名称永远不会在它是否引用一个类型方面有歧义,因此它从不需要typename
也typename
因此不允许存在。
(1)这种松动在标准中并没有真正明确地说明,而是从几个规则的组合中得出的。基本上,只要允许使用简单类型说明符(表示类型的东西),语法也允许使用类型名称说明符(以 为前缀的限定名称typename
)。模板规则(主要在 14.6 中)仅说明typename
当依赖限定名称表示类型时需要。由于在其他上下文中没有任何禁止typename
,它可以与任何表示类型的限定名称一起使用(甚至在模板上下文之外)。