typename 关键字和嵌套名称说明符
typename keyword and nested name specifier
struct A{};
template <typename T>
struct B
{
typename ::A a1; //(1)
typename A a2; //(2): error
};
int main(){return 0;}
为什么第一种情况正确,而第二种情况不正确?我不明白那个限制的意思。
无论如何,为什么允许第一种情况? ::A
不是依赖于模板参数的名称。什么意思?
正如 所解释的那样,严格按照标准(C++11,我手头没有 C++14 文本),情况 (1) 实际上也应该是错误的 - typename
仅当 ::
.
的左侧至少有一个名称时,才能使用前缀限定名称
然而,正如@hvd 在评论中指出的那样,CWG issue 382 表示实际意图是允许 typename
在任何限定名称之前,包括全局命名空间限定。由于这是大多数编译器似乎要实现的,因此该答案的其余部分遵循这个想法。
这样看,情况(2)不是限制,情况(1)是仁。所需的规则(我相信它的原始措辞)基本上是 "if a qualified name which depends on template parameters denotes a type, you must prefix it with typename
." 为方便起见,它被放宽为“typename
可用于定义类型的任何限定名称,无论它是依赖的还是不是。"(1)
相比之下,非限定名称在是否引用类型方面永远不会有歧义,因此它永远不需要 typename
,因此那里不允许 typename
。
(1)这个松动在标准中并没有真正明确说明,而是几个规则的组合。基本上,只要 simple-type-specifier(表示类型的东西)被允许,语法也允许 typename-specifier(一个合格的以 typename
为前缀的名称)。模板规则(主要在 14.6 中)仅声明当从属限定名表示类型时需要 typename
。由于在其他上下文中没有禁止 typename
,因此它可以与表示类型的任何限定名称一起使用(即使在模板上下文之外)。
如果类型嵌套在从属范围中,则规则不是您只能使用 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 之前,第一个也是被禁止的,因为全局限定符 ::
与该语法不匹配。
struct A{};
template <typename T>
struct B
{
typename ::A a1; //(1)
typename A a2; //(2): error
};
int main(){return 0;}
为什么第一种情况正确,而第二种情况不正确?我不明白那个限制的意思。
无论如何,为什么允许第一种情况? ::A
不是依赖于模板参数的名称。什么意思?
正如 typename
仅当 ::
.
然而,正如@hvd 在评论中指出的那样,CWG issue 382 表示实际意图是允许 typename
在任何限定名称之前,包括全局命名空间限定。由于这是大多数编译器似乎要实现的,因此该答案的其余部分遵循这个想法。
这样看,情况(2)不是限制,情况(1)是仁。所需的规则(我相信它的原始措辞)基本上是 "if a qualified name which depends on template parameters denotes a type, you must prefix it with typename
." 为方便起见,它被放宽为“typename
可用于定义类型的任何限定名称,无论它是依赖的还是不是。"(1)
相比之下,非限定名称在是否引用类型方面永远不会有歧义,因此它永远不需要 typename
,因此那里不允许 typename
。
(1)这个松动在标准中并没有真正明确说明,而是几个规则的组合。基本上,只要 simple-type-specifier(表示类型的东西)被允许,语法也允许 typename-specifier(一个合格的以 typename
为前缀的名称)。模板规则(主要在 14.6 中)仅声明当从属限定名表示类型时需要 typename
。由于在其他上下文中没有禁止 typename
,因此它可以与表示类型的任何限定名称一起使用(即使在模板上下文之外)。
如果类型嵌套在从属范围中,则规则不是您只能使用 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 之前,第一个也是被禁止的,因为全局限定符 ::
与该语法不匹配。