C++ typename关键字和嵌套名称说明符 struct A{}; 模板 结构B { typename::a1;//(1) typename A a2;//(2):错误 }; int main(){return 0;}

C++ typename关键字和嵌套名称说明符 struct A{}; 模板 结构B { typename::a1;//(1) typename A a2;//(2):错误 }; int main(){return 0;},c++,templates,typename,dependent-name,C++,Templates,Typename,Dependent Name,为什么第一种情况是正确的,而第二种情况不是?我不明白那个限制的含义。 不管怎样,为什么第一个案例是允许的::A不是依赖于模板参数的名称。它的意思是什么?正如所解释的,严格按照标准(C++11,我手头没有C++14文本),大小写(1)实际上也应该是错误的-typename前缀限定名只能在:左侧至少有一个名称时使用 然而,@hvd在注释中指出,实际意图是在任何限定名称(包括全局命名空间限定)之前允许typename。因为大多数编译器似乎都实现了这一点,所以下面的答案就是这个想法 当这样看时,情况(2

为什么第一种情况是正确的,而第二种情况不是?我不明白那个限制的含义。
不管怎样,为什么第一个案例是允许的<代码>::A不是依赖于模板参数的名称。它的意思是什么?

正如所解释的,严格按照标准(C++11,我手头没有C++14文本),大小写(1)实际上也应该是错误的-
typename
前缀限定名只能在
左侧至少有一个名称时使用

然而,@hvd在注释中指出,实际意图是在任何限定名称(包括全局命名空间限定)之前允许
typename
。因为大多数编译器似乎都实现了这一点,所以下面的答案就是这个想法

当这样看时,情况(2)不是限制,而是情况(1)是仁慈。所需的规则(我相信是它最原始的措辞)基本上是“如果依赖于模板参数的限定名表示类型,则必须在其前面加上
typename
”为方便起见,将其放宽为“
typename
可用于任何不依赖类型的限定名。”(1)

相反,非限定名称在是否引用类型方面永远不会模棱两可,因此它从不需要
typename
,因此不允许使用
typename



(1) 标准中并未明确规定这种放松,但遵循了多种规则的组合。基本上,只要允许使用简单类型说明符(表示类型的东西),语法也允许使用类型名说明符(前缀为
typename
)的限定名)。模板规则(主要在14.6中)仅规定当依赖限定名表示类型时,需要
typename
。由于在其他上下文中没有任何内容禁止使用
typename
,因此它可以与表示类型的任何限定名称一起使用(即使在模板上下文之外)。

规则不是,如果类型嵌套在依赖范围中,则只能使用
typename
。规则大致如下:

  • 如果它在从属范围内,则必须使用
    typename
  • 只能在语法允许的情况下使用
    typename
语法允许它作为限定id的子集,由

struct A{};

template <typename T>
struct B
{
    typename ::A a1; //(1)
    typename A a2; //(2): error
};

int main(){return 0;}
typename说明符:
typename嵌套名称说明符标识符
typename嵌套名称说明符模板简单模板id
嵌套名称说明符:
:(C++14或更高版本)
::类型名称::
::命名空间名称::
decltype说明符::
嵌套名称说明符标识符::
嵌套名称说明符模板简单模板id::

因此,第二种情况当然是禁止的,因为它不涉及任何筑巢。严格地说,在C++14之前,第一个也是被禁止的,因为全局限定符
与该语法不匹配。

您的示例运行良好:。出示原件code@user2451677未能在g++和clang++中编译我真的希望在这个问题上有一个非常好的答案。我对此很感兴趣。我并不是妄想以为我知道C++中的一切,但我想至少我知道我知道什么,什么不知道,但是总有人告诉我我不知道蹲下。@ USE2451677你所搜索的词是不符合的:尽管在过去几年里,为了使VC进入C++ 14,已经做了大量的努力。标准。@LightnessRacesinOrbit Herb Sutter说VC直接针对C++14,在实现许多C++11功能之前,先实现C++14功能,如通用lambdas。我的注释:他们没有选择C++方言的选项,所以我想这对他们来说是有意义的。我正在努力寻找标准中的便利性的确切措辞;一旦我成功,我会把它添加到答案中。甚至没有任何要求
typename
只能在模板中使用<代码>结构S{};typename::S完全有效。@bolov:
::A
没有歧义;但是有些限定id是,语法只是指定(或多或少)您可以对任何限定id使用
typename
,而不管是否有必要避免歧义。非限定id不能含糊不清,并且语法不允许将
typename
与其中一个一起使用。尽管根据我对语法的阅读,
typename::A
无效。typename说明符不允许任何限定id,只允许那些涉及嵌套名称说明符的id,这涉及嵌套在命名类型或命名空间中
本身并不是其中之一。@hvd:事实上,我的评论已经过时了。C++14似乎添加了
作为嵌套名称说明符(参考)。
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 ::