12

以下代码在 g++ 和 clang 中正确编译:

template<typename T>
struct foo
{
    class iterator;
    using bar = foo::iterator;
};

int main() {}

但是 MSVC 2013 给出了以下错误:

foo.cpp(9): error C2061: syntax error : identifier 'iterator'
          foo.cpp(10) : see reference to class template instantiation 'foo<T>' being compiled
foo.cpp(9): error C2238: unexpected token(s) preceding ';'

如果我将该行更改为:

using bar = typename foo::iterator;

然后所有三个编译器都成功编译它。原版正确吗?(即这是一个 MSVC 错误,还是 gcc/clang 扩展)

4

2 回答 2

7

[温度分辨率]/p3:

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

[temp.dep.type]/p1:

名称指的是当前实例化,如果它是

  • 在类模板、类模板的嵌套类、类模板的成员或类模板的嵌套类的成员的定义中,类模板的注入类名(第 9 条)或嵌套类,
  • [...]

[temp.dep.type]/p4:

一个名称是当前实例化的成员,如果它是

  • 一个非限定名称,当查找时,它指的是作为当前实例化的类的至少一个成员或其非依赖基类。[注意:只有在类模板定义所包含的范围内查找名称时,才会发生这种情况。——<em>尾注]
  • 一个限定 ID,其中嵌套名称说明符指的是当前实例化,并且在查找时指代作为当前实例化或其非依赖基类的类的至少一个成员。[注意:如果没有找到这样的成员,并且当前实例化有任何依赖的基类,那么qualified-id是未知特化的成员;见下文。——<em>尾注]
  • [...]

foo是当前的实例化。foo::iterator是一个限定标识,其中嵌套名称说明符( foo::) 指的是当前实例化,并且在查找时,“指的是作为当前实例化的类的至少一个成员或其非依赖基类” ; 因此它是当前实例化的成员。因此,[temp.res]/p3 不适用,typename不需要。您仍然可以添加一个 - 或者直接使用iteratorunqualified。

于 2015-05-13T04:37:18.407 回答
2

从标准:

14.6.2.1 依赖类型[temp.dep.type]

1 名称指的是当前实例化,如果它是

__ 在类模板、类模板的嵌套类、类模板的成员或类模板的嵌套类的成员的定义中,类模板的注入类名(第 9 条)或嵌套类,

该名称foo指的是当前的实例化,这是显而易见的。

由于iterator在模板的定义中被声明为嵌套类,所以iterator指的是foo. foo::iterator是一样的iterator

using bar = foo::iterator;

using bar = iterator;

应该管用。

在我看来,您遇到了 MSVC 缺陷。

于 2015-05-13T04:42:42.427 回答