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
...
This typedef can also be used with structures of C language. Here how it looks like: Here nameOfType correspond to the definition of structure allied with it. Now, this nameOfType can be implemented by declaring a variable of this structure type.
If the typedef name is the same as a class type name, it can only be so if that typedef is a synonym of the class name. A C++ class defined in a typedef definition without being named is given a dummy name. Such a class cannot have constructors or destructors.
The name space for a typedef name is the same as other identifiers. When an object is defined using a typedef identifier, the properties of the defined object are exactly the same as if the object were defined by explicitly listing the data type associated with the identifier.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With