【问题标题】:Is "typename" allowed/required in C++11 using-declaration?在 C++11 using-declaration 中是否允许/需要“typename”?
【发布时间】:2015-07-24 04:35:29
【问题描述】:

以下代码在 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 扩展)

【问题讨论】:

  • 允许,是的。必须的,没有。 foo::iterator 命名当前实例化的成员。

标签: c++ c++11 typename using-declaration


【解决方案1】:

[temp.res]/p3:

qualified-id 旨在引用不是 当前实例化 (14.6.2.1) 的成员及其 nested-name-specifier是一个依赖类型,需要以关键字typename为前缀,形成一个typename-specifier

[temp.dep.type]/p1:

一个名字指的是当前的实例化如果它是

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

[temp.dep.type]/p4:

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

  • 一个非限定名称,在查找时,它指的是当前实例化或非依赖类的至少一个成员 其基类。 [ 注意:这只能在查找 类模板定义所包含的范围内的名称。 ——结束 注意 ]​​i>
  • 一个 qualified-id,其中 nested-name-specifier 指的是当前实例化,并且在查找时指的是至少一个 是当前实例化或非依赖类的成员 其基类。 [ 注意:如果没有找到这样的成员,并且 当前实例化有任何依赖的基类,那么 qualified-id 是未知专业的成员;见下文。 —尾注 ]​​i>
  • [...]

foo 是当前实例化。 foo::iterator 是一个 qualified-id,其中 nested-name-specifier (foo::) 指的是当前实例化,当查找时,“指的是当前实例化的类的至少一个成员或其非依赖基类”;因此它是当前实例化的成员。因此,[temp.res]/p3 不适用,也不需要typename。您仍然可以添加一个 - 或者直接使用不合格的iterator

【讨论】:

  • 我认为这样做,你发现它更快,+1 :)
【解决方案2】:

来自标准:

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

1 一个名字指的是当前的实例化,如果它是

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

名称foo指的是当前的实例化,这很明显。

由于iterator在模板定义中被声明为嵌套类,iterator指的是foo的当前实例化中的名称。 foo::iteratoriterator 相同。

using bar = foo::iterator;

还有

using bar = iterator;

应该可以。

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

【讨论】:

    猜你喜欢
    • 2012-05-17
    • 2020-08-06
    • 1970-01-01
    • 2010-10-18
    • 1970-01-01
    相关资源
    最近更新 更多