Reputation: 153
I came across some unexpected behaviour the other day and reduced it to these few lines of code. I tested it out on VC++ 19.0, Clang 3.8, and GCC 5.4.0 as well as 8.2.0. The output in each case is just 1
whereas I had expected it to precede with Hello
and complete with Goodbye
.
#include <iostream>
template <class T> struct X { static T data; };
template <class T> T X<T>::data;
struct A
{
A()
{
std::cout << "Hello" << std::endl;
}
~A()
{
std::cout << "Goodbye" << std::endl;
}
};
struct B : X<A> { };
int main(int argc, char **argv)
{
std::cout << sizeof(B::data) << std::endl;
}
Obviously B::data
exists but its constructor and destructor are never called. Interestingly, if I add this for a test
assert(typeid(B::data) == typeid(A));
GCC behaves as I had originally expected it to but both Clang and VC++ behave as before. So my suspicion here is that the behaviour is undefined rather than just unexpected. I'm not familiar enough with the language standard wording to say for myself exactly what the violation is in this case. But it certainly runs against my intuitions about how both static members and inheritance works.
Upvotes: 1
Views: 93
Reputation: 2649
Accessing a static member of a struct doesn't instantiate it and so the constructor of the struct X<A>
in your case is never called.
You can even simplify your code to try without template as it doesn't affect the outcome here.
Upvotes: 0
Reputation: 13040
According to [temp.inst]/3:
... in particular, the initialization (and any associated side effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
and [expr.context]/1:
[ Note: In an unevaluated operand, a non-static class member may be named ([expr.prim.id]) and naming of objects or functions does not, by itself, require that a definition be provided ([basic.def.odr]). ... — end note ]
X<A>::data
is only used as the operand of sizeof
, which is an unevaluated operand, hence X<A>::data
is not initialized.
For the case of typeid
, I think it is a GCC bug.
Upvotes: 1