1

typename在以下示例中,clang 3.6 和 gcc 5.0 都需要:

template<typename T>
struct B
{
    typedef int Type;
};

void f(int);

template<int n>
struct A
{
    typedef typename B<decltype(f(n))>::Type Type;
};

C++11 标准中的以下措辞涵盖了这一点:

[温度.dep.type]/5

一个名字是一个未知专业化的成员,如果它是

  • 一个限定 ID,其中嵌套名称说明符命名了一个不是当前实例化的依赖类型。

[温度.dep.type]/8

一个类型是依赖的,如果它是

  • 未知专业的成员,

  • 一个 simple-template-id,其中模板名称是模板参数或任何模板参数是依赖类型或依赖于类型或值的表达式

  • 由 表示decltype(expression),其中表达式依赖于类型

这表明B<decltype(f(n))>::Type仅当依赖于B<decltype(f(n))>类型时才依赖于类型。同样,B<decltype(f(n))>仅当依赖于f(n)类型时才依赖。

[temp.dep.expr]/1

除非下面描述,如果任何子表达式是类型相关的,则表达式是类型相关的。

[temp.dep.expr]/3

一个 id 表达式是依赖于类型的,如果它包含

  • 一个标识符,通过名称查找与使用依赖类型声明的一个或多个声明相关联,

  • 一个依赖的模板ID,

  • 指定依赖类型的转换函数 ID,或

  • 命名未知专业化成员的嵌套名称说明符或限定 ID;

或者,如果它为某些 T 命名当前实例化的具有类型“T 的未知边界数组”的静态数据成员

这表明f(n)仅当依赖于类型时才依赖n于类型,而不依赖于类型。n

我错过了什么,或者这是一个编译器错误?

4

1 回答 1

2

您的分析有点不完整,但在其他方面是正确的。

qualified-id旨在引用不是当前实例化(14.6.2.1)成员的类型并且其 nested-name-specifier引用依赖类型时,应以关键字为前缀typename,形成类型名-说明符

显然B<…&gt;::Type不能引用当前实例化的成员。所以问题是是否B<decltype(f(n))>是依赖类型。

一个类型是依赖的,如果它是

  • […]
  • 未知专业的成员,
  • […]
  • 一个simple-template-id,其中模板名称是模板参数或任何模板参数是依赖类型或依赖于类型或值的表达式,或
  • 用 表示decltype(expression),其中表达式取决于类型 (14.6.2.2)。

f(n)不依赖于类型,因为没有子表达式,因此decltype(f(n))不是依赖类型。
此外,decltype(...)不能依赖于值,因为它不是常量表达式1并且 [temp.dep.constexpr] 中没有其他段落适用。显然decltype(f(n))也不依赖于类型。
至少但不是最后一个,只有当模板参数是依赖类型2B<decltype(f(n))>::Type时,它才会成为未知专业化的成员,我们得出结论它不是。

因此,根据我的解释,编译器是不正确的,并且typename不需要关键字。


1事实上,decltype(…)根本不是一个表达式。

2 [temp.dep.type]/5:

一个名字是一个未知专业化的成员,如果它是

  • 一个限定 ID ,其中嵌套名称说明符命名了一个不是当前实例化 的依赖类型。
  • 一个qualified-id,其中nested-name-specifier引用当前实例化,当前实例化至少有一个依赖的基类,并且该qualified-id的名称查找没有找到作为当前实例化的类的任何成员或其非依赖基类。
  • 一个id 表达式,表示类成员访问表达式 (5.2.5) 中的成员,其中任一
    • […]
于 2014-12-31T11:30:24.360 回答