Search code examples
c++templatesexplicit-instantiationstatic-order-fiasco

Order of initialization of static member of explicitly instantiated template and another static variable


This is the simplified form of my problem (based on a real library):

// class template with static member variable:
template <typename T>
struct X 
{
  static std::vector<T> v_;
};

// definition of that static member variable:
template <typename T>
std::vector<T> X<T>::v_{};

// explicit instantiation of the class template:
template struct X<int>;

// library initialization function that fills v_ for X<int>:
static bool init()
{
  X<int>::v_.reserve(1000);
  ...
  return true;
}

// automatic initialization:
static bool initialized = init();

My question is whether it is guaranteed in this case (single translation unit) — by the order of definitions and instantiation — that X<int>::v_ will be initialized before init() function is invoked.


AFAIK, static variables are initialized in a single translation unit in order of their definitions, but can templates and explicit instantiation change something about it? What if that explicit instantiation was removed? Or, put at the end of the source code?


Solution

  • [basic.start.dynamic]:

    Dynamic initialization of a non-local variable with static storage duration is unordered if the variable is an implicitly or explicitly instantiated specialization, is partially-ordered if the variable is an inline variable that is not an implicitly or explicitly instantiated specialization, and otherwise is ordered.

    [Note 1: An explicitly specialized non-inline static data member or variable template specialization has ordered initialization. — end note]

    as standard points out, the initialization of v_ is unordered.

    but always we can solve this problem by static function:

    template<typename T>
    struct X{
        static std::vector<T>& v_() noexcept {
            static std::vector<T> v;
            return v;
        }
    };
    template struct X<int>;
    static bool init(){
        X<int>::v_().reserve(1000);
        // ...
        return true;
    }
    static bool initialized = init();