在GNU编译器中,typedef的名称查找是错误的吗?

GSi*_*GSi 7 c++ typedef language-lawyer name-lookup c++11

以下代码

#include <iostream>

typedef double A; // a global typedef

template <class Z> struct B // a template class...
{
    A i{22.2}; // global typedef is in scope
    typedef int A; // now  a local typedef with the same name is introduced
    A b{24};  // now the local typedef is in scope
    Z c{36}; // a simple member of the template type
};

template <class Z> struct C : B<Z> // a template struct inheriting B
{
    A a;  // global typedef is in scope because we are in a template struct
    C(  ) : a(2.2){  }
};

int main(  )
{
    C<int> c;
    std::cout << "c's members: "
           << c.a << ' '
           << c.i << ' '
           << c.b << ' '
           << c.c << std::endl;
    std::cout << "their sizeof: "
           << sizeof(c.a) << ' ' 
           << sizeof(c.i) << ' '
           << sizeof(c.b) << ' '
           << sizeof(c.c) <<  std::endl;
}
Run Code Online (Sandbox Code Playgroud)

不是由GNU-g++ 4.9.2它编写的,而是clang 3.5.0按照我在嵌入式注释中尝试解释的行为,并且可以通过生成的输出看到它.这是GNU编译器中的错误吗?诊断说该行在typedef int A;范围内 struct B

错误:从'typedef double A'更改'A'的含义

请注意,当层次不进行的template(当然还有Z c{36};声明被移除)通过执行查找clang在范围C(正常,如我想)发现typedef在的范围B,认为所述构件a为类型int; 然后它发出关于缩小初始化double常数的警告2.2......

eer*_*ika 9

来自c ++标准草案(N4140)

§3.3.7[basic.scope.class]

2)在S类中使用的名称N应在其上下文中引用相同的声明,并在完成的S范围内重新评估.违反此规则不需要诊断.

A i{22.2}最初指的是全球性的::A.但是在B::A声明之后,当在完成的范围内重新评估时B,它将参考B::A.这违反了上述规则.

要修复它,请使用完全限定名称:::A i{22.2}.即使声明后::A总是指全局,所以它不违反规则.AB::A

这不是g ++中的错误; 这只是一个不合理的计划.编译器不需要为违反规则提供诊断,但也不需要接受它.