简体   繁体   中英

name lookup for typedef is buggy in GNU compiler?

The following code

#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;
}

is NOT compiled by GNU-g++ 4.9.2 while it is by clang 3.5.0 and behaves as I tried to explain in the embedded comments and as it can be seen by the output produced. Is this a bug in the GNU compiler? The diagnostic says that the line typedef int A; in the scope of the struct B

error: changes meaning of 'A' from 'typedef double A'

Note that when the hierarchy is not made of template (and of course the Z c{36}; declaration is removed) the lookup performed by clang in the scope of C (correctly, as I suppose) finds the typedef in the scope of B and considers the member a to be of type int ; then it issues a warning about the narrowing of the initializing double constant 2.2 ...

From the c++ standard draft (N4140)

§3.3.7 [basic.scope.class]

2) A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule.

A i{22.2} initially refers to the global ::A . But after B::A is declared, when re-evaluated in the completed scope of B , it would refer to B::A . This violates the rule above.

To fix it, use the fully qualified name: ::A i{22.2} . ::A always refers to the global A even after B::A is declared, so it doesn't violate the rule.

This is not a bug in g++; it's just an ill-formed program. The compiler is not required not give you a diagnostic for the violation of the rule, but it's not required to accept it either.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM