c++ - Initialization of a static member inside a template -


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