struct A{};
template <typename T>
struct B
{
typename ::A a1; //(1)
typename A a2; //(2): error
};
int main(){return 0;}
为什么第一种情况是正确的,而第二种情况却不正确?我不明白这个限制的含义。
无论如何,为什么允许第一种情况? ::A
不是模板参数依赖名称。这是什么意思?
规则不是只有在类型嵌套在依赖作用域中时才能使用 typename
。规则或多或少是:
- 如果
typename
在依赖作用域中,则必须使用 - 您只能在语法允许的情况下使用
typename
。
语法允许它用于限定 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 第 382 期表明实际意图是允许在任何限定名称(包括全局命名空间限定)之前使用typename
。由于这是大多数编译器似乎实现的内容,因此本答案的其余部分遵循此想法。
这样看,不是情况(2)是限制,而是情况(1)是仁慈。所需的规则(我相信其原始措辞)基本上是"如果依赖于模板参数的限定名称表示类型,则必须在它前面加上typename
"。为方便起见,它被放宽为"typename
可用于任何限定名称,无论它是否依赖类型。(1)
相比之下,非限定名称在是否引用类型方面永远不会模棱两可,因此它从不需要typename
因此不允许使用typename
。
(1)这种松动并没有在标准中明确规定,而是从几个规则的组合中得出的。基本上,只要允许使用简单类型说明符(表示类型的东西),语法也允许使用类型名说明符(前缀为 typename
的限定名)。模板的规则(主要在 14.6 中)仅声明当依赖限定名表示类型时需要typename
。由于没有任何东西禁止在其他上下文中typename
,因此它可以与表示类型的任何限定名称一起使用(即使在模板上下文之外)。