"typename" allowed/required 在 C++11 中使用声明吗?
Is "typename" allowed/required in C++11 using-declaration?
以下代码可在 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 扩展)
[temp.res]/p3:
When a qualified-id is intended to refer to a type that is not a
member of the current instantiation (14.6.2.1) and its
nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword typename
, forming a typename-specifier.
[temp.dep.type]/p1:
A name refers to the current instantiation if it is
- in the definition of a class template, a nested class of a class template, a member of a class template, or a member of a nested class
of a class template, the injected-class-name (Clause 9) of the class
template or nested class,
- [...]
[temp.dep.type]/p4:
A name is a member of the current instantiation if it is
- An unqualified name that, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent
base class thereof. [ Note: This can only occur when looking up a
name in a scope enclosed by the definition of a class template. —end
note ]
- A qualified-id in which the nested-name-specifier refers to the current instantiation and that, when looked up, refers to at least one
member of a class that is the current instantiation or a non-dependent
base class thereof. [ Note: if no such member is found, and the
current instantiation has any dependent base classes, then the
qualified-id is a member of an unknown specialization; see below.
—end note ]
- [...]
foo
是当前实例化。 foo::iterator
是一个 qualified-id,其中 nested-name-specifier (foo::
) 指的是当前实例化,当查找时,"refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof";因此它是当前实例化的成员。因此,[temp.res]/p3 不适用,不需要 typename
。您仍然可以添加一个 - 或者直接使用 iterator
不合格。
来自标准:
14.6.2.1 Dependent types [temp.dep.type]
1 A name refers to the current instantiation if it is
__ in the definition of a class template, a nested class of a class template, a member of a class template, or a member of a nested class of a class template, the injected-class-name (Clause 9) of the class template
or nested class,
名称foo
指的是当前实例化,这是显而易见的。
由于iterator
在模板定义中声明为嵌套的class,因此iterator
指的是foo
当前实例化中的名称。 foo::iterator
等同于 iterator
.
using bar = foo::iterator;
以及
using bar = iterator;
应该可以。
在我看来,您 运行 存在 MSVC 缺陷。
以下代码可在 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 扩展)
[temp.res]/p3:
When a qualified-id is intended to refer to a type that is not a member of the current instantiation (14.6.2.1) and its nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword
typename
, forming a typename-specifier.
[temp.dep.type]/p1:
A name refers to the current instantiation if it is
- in the definition of a class template, a nested class of a class template, a member of a class template, or a member of a nested class of a class template, the injected-class-name (Clause 9) of the class template or nested class,
- [...]
[temp.dep.type]/p4:
A name is a member of the current instantiation if it is
- An unqualified name that, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof. [ Note: This can only occur when looking up a name in a scope enclosed by the definition of a class template. —end note ]
- A qualified-id in which the nested-name-specifier refers to the current instantiation and that, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof. [ Note: if no such member is found, and the current instantiation has any dependent base classes, then the qualified-id is a member of an unknown specialization; see below. —end note ]
- [...]
foo
是当前实例化。 foo::iterator
是一个 qualified-id,其中 nested-name-specifier (foo::
) 指的是当前实例化,当查找时,"refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof";因此它是当前实例化的成员。因此,[temp.res]/p3 不适用,不需要 typename
。您仍然可以添加一个 - 或者直接使用 iterator
不合格。
来自标准:
14.6.2.1 Dependent types [temp.dep.type]
1 A name refers to the current instantiation if it is
__ in the definition of a class template, a nested class of a class template, a member of a class template, or a member of a nested class of a class template, the injected-class-name (Clause 9) of the class template or nested class,
名称foo
指的是当前实例化,这是显而易见的。
由于iterator
在模板定义中声明为嵌套的class,因此iterator
指的是foo
当前实例化中的名称。 foo::iterator
等同于 iterator
.
using bar = foo::iterator;
以及
using bar = iterator;
应该可以。
在我看来,您 运行 存在 MSVC 缺陷。