I'm trying to have a better understanding about the initialization of static members in templated classes / structs.
Let's take the following minimal example (available in Coliru):
#include <iostream>
struct A {
int value;
A(int val) : value{val} { std::cout << "A(" << value << ")\n"; }
};
struct Static {
static inline A s_a{42};
static void use() {
std::cout << s_a.value++ << '\n';
std::cout << s_a.value << '\n';
}
};
struct User {
User() {
Static::use();
}
};
User s_user{};
int main() {
return 0;
}
The output is (as I should expect):
A(42)
42
43
Now, I'd like to be able to have several versions of Static
for different types, so I convert it into a template (Coliru):
#include <iostream>
struct A {
int value;
A(int val) : value{val} { std::cout << "A(" << value << ")\n"; }
};
template<class T>
struct Static {
static inline A s_a{42};
static void use() {
std::cout << s_a.value++ << '\n';
std::cout << s_a.value << '\n';
}
};
struct User {
User() {
Static<int>::use();
}
};
User s_user{};
int main() {
return 0;
}
but then the output is
0
1
A(42)
As you can see, A::value
is being used uninitialized, and A
's constructor is called after Static<int>::use
has been executed.
I can change the definition of the s_a
so it is specialized in advanced:
template<class T>
struct Static {
static A s_a;
// ...
};
template<> A Static<int>::s_a{42};
and it works correctly (Coliru). The counterpart is that I have to define every single specialization and I'd like to make it as easier to use as possible (as you can suppose actual code is more complex).
So, my questions are:
Why is
Static<T>::use()
usings_a
before it (s_a
) is initialized? I can think about some kind of delayed initialization until specialization (sorry, don't know the correct name for it), and thatUser<
is calling a static function that, somehow, is not related to the static attribute (only that they are in the same encapsulation), but I don't know exactly why nor what the standard has to say about it.How should I change this code to get the same behavior as the non-templated version? It is, that the attributes of any
Static<T>
can be initialized before their static methods are called.
Note: struct A
is just a minimum example here, in the project I'm working on it is a templated class that is specialized based on Static<T>
.