typename关键字和嵌套名称说明符

时间:2015-01-06 12:16:59

标签: c++ templates typename dependent-name

struct A{};

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

int main(){return 0;}

为什么第一种情况正确,但第二种情况不正确?我不明白这种限制的含义 无论如何,为什么第一个案例被允许? ::A不依赖于模板参数的名称。它的含义是什么?

2 个答案:

答案 0 :(得分:6)

规则并不是如果类型嵌套在依赖范围内,则只能使用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之前,第一个也被禁止,因为全局限定符::与该语法不匹配。

答案 1 :(得分:5)

正如@MikeSeymour's answer解释的那样,严格遵循标准(C ++ 11,我手边没有C ++ 14文本),案例(1)实际上也应该是错误的 - 只有在typename左侧至少有一个名称时,才能使用::作为限定名称的前缀。

但是,正如@hvd在评论中指出的那样,CWG issue 382表示实际意图是在任何限定名称之前允许typename,包括全局命名空间限定。由于这是大多数编译器似乎实现的,所以本答案的其余部分都遵循这个想法。

当这样看时,并非如果情况(2)是限制,那么情况(1)就是仁慈。所需的规则(以及我非常原始的措辞,我相信)基本上是&#34;如果依赖于模板参数的限定名称表示类型,则必须在其前面添加typename。&#34;为方便起见,它被放宽为&#34; typename可以用于任何类型的合格名称,无论它是否依赖。&#34; (1)

相比之下,非限定名称永远不会含糊不清,无论它是否引用某种类型,因此永远不需要typename,因此不允许typename


(1)这种放松并没有在标准中明确说明,而是来自几个规则的组合。基本上,只要允许简单类型说明符(表示类型的东西),语法也允许 typename-specifier (前缀为{{1的限定名称) }})。模板规则(主要在14.6中)仅表示当从属限定名称表示类型时需要typename。由于在其他上下文中没有禁止typename,因此它可以与任何表示类型的限定名称一起使用(甚至在模板上下文之外)。