以下代码在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扩展名)
答案 0 :(得分:7)
[temp.res] / P3:
当 qualified-id 旨在引用不是a的类型时 当前实例化的成员(14.6.2.1)及其成员 nested-name-specifier 是指依赖类型,它应以关键字
typename
作为前缀,形成 typename-specifier 。
[temp.dep.type] / P1:
名称是指当前实例化,如果它是
- 在类模板的定义中,类模板的嵌套类,类模板的成员或嵌套类的成员 类模板,类的注入类名(第9节) 模板或嵌套类,
- [...]
[temp.dep.type] / P4:
名称是当前实例化的成员,如果它是
- 一个非限定名称,当查找时,指的是当前实例化或非依赖项的类的至少一个成员 基类。 [注意:这只能在查找时发生 由类模板定义包含的范围中的名称。 - 端 注意]
- qualified-id ,其中嵌套名称说明符引用当前实例化,并且当查找时,指的是至少一个 作为当前实例化或非依赖类的类的成员 基类。 [注意:如果找不到这样的成员,那么 当前实例化有任何依赖的基类,然后是 qualified-id是未知专业化的成员;见下文。 - 结束记录]
- [...]
foo
是当前的实例化。 foo::iterator
是 qualified-id ,其中嵌套名称说明符(foo::
)引用当前实例化,当查找时, &#34;指的是当前实例化或其非依赖基类的类的至少一个成员&#34 ;;因此它是当前实例化的成员。因此,[temp.res] / p3不适用,不需要typename
。您仍然可以添加一个 - 或者直接使用iterator
不合格。
答案 1 :(得分: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缺陷。