here's minimal example:
#include <iostream> struct b { b() { x = 42; } static int x; }; int b::x; template <int n> struct { int foo() { return b.x; } static b b; }; template<int n> b a<n>::b; //template struct a<2>; // explicit instantiation n = 2 (!) int main(int argc, char **argv) { std::cout << a<1>().foo() << std::endl; return 0; } this program writes 42 using g++ 4.9.2, writes 0 using visual studio 2015 rc. also, if uncomment explicit instantiation, vs2015rc gives 42, quite interesting, template parameter here different 1 used in main function.
is bug? assume g++ correct, there reference b inside foo, b's constructor should called.
edit: there simple workaround - if there non-static variable in b, referenced in a, vs2015rc compile correctly:
// ... struct b { b() { x = 42; } static int x; int y; // <- non-static variable }; // ... template <int n> struct { int foo() { b.y; return b.x; } // <- reference b.y static b b; }; this seems work, though b.y, statement, nop.
from [basic.start.init]:
variables static storage duration (3.7.1) or thread storage duration (3.7.2) shall zero-initialized (8.5) before other initialization takes place. constant initializer object o expression constant expression, except may invoke constexpr constructors o , subobjects if objects of non-literal class types. [ ... ]
together, zero-initialization , constant initialization called static initialization; other initialization dynamic initialization. static initialization shall performed before dynamic initialization takes place.
in our case, b statically initialized b.x dynamically initialized (the constructor isn't constexpr). have:
it implementation-defined whether dynamic initialization of non-local variable static storage duration done before first statement of main. if initialization deferred point in time after first statement of main, shall occur before first odr-use (3.2) of function or variable defined in same translation unit variable initialized.
odr-used means, [basic.def.odr]:
a variable x name appears potentially-evaluated expression ex odr-used ex unless applying lvalue-to-rvalue conversion (4.1) x yields constant expression (5.20) not invoke nontrivial functions and, if [ ... ]
but evaluating b.x not yield constant expression, can stop there - b.x odr-used a<n>::foo(), first odr-use. while initialization not have occur before main(), have occur before foo(). if 0, that's compiler error.
Comments
Post a Comment