类型名称关键字和嵌套名称说明符

typename keyword and nested name specifier

本文关键字:说明符 嵌套 关键字 类型      更新时间:2023-10-16
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,因此它可以与表示类型的任何限定名称一起使用(即使在模板上下文之外)。