So I'm trying to create a factory based on CRTP. For simplicity, I will just include whatever is relevant here. I got two questions which might be irrelevant to each other, but was stuck trying to find the keywords.
#include <bits/stdc++.h>
using namespace std;
static auto& GetFactoryMap() {
static vector<string> GLOBAL_FACTORY_MAP;
return GLOBAL_FACTORY_MAP;
}
template <typename Derived>
struct Registrar {
static int DoRegister() {
auto name = typeid(Derived).name();
GetFactoryMap().emplace_back(name);
return 1;
};
inline static const int _hello = DoRegister();
};
struct Foo : public Registrar<Foo> {};
int main() {
cout << GetFactoryMap().size();
}
Compiled with x86-64 clang-8.0.0
, flag -std=c++17
.
QUESTION 1: The program returned 0
: https://godbolt.org/z/5c74TePT5. I expected it to print 1
as defining the class Foo
should also define a Registrar<Foo>
, which in turn will initialise the _hello
and call DoRegister()
.
But when I do this:
int main() {
cout << Foo::_hello << endl;
cout << GetFactoryMap().size();
}
Then it did print 1
(the _hello
) and 1
(the map size).
QUESTION 2: so I found out how to solve the first issue by dummy-calling _hello
inside Registrar
constructor.
template <typename Derived>
struct Registrar {
Registrar() {
(void)_hello;
}
...
}
But thing is, I still don't know WHY it can fix the issue. And even after I did that, the DoRegister
seemed to only get called if I have an empty constructor OR a default constructor OUTSIDE the class definition, as seen by the global map size is only 2: https://godbolt.org/z/Me53q1x86.
What is happening here?
Unless a member of a templated class is a declared specialization, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist or if the existence of the definition of the member affects the semantics of the program; 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.
TL;DR If it's not used, it's not instantiated.
Explicitly-defaulted functions
A non-user-provided defaulted function (i.e., implicitly declared or explicitly defaulted in the class) that is not defined as deleted is implicitly defined when it is odr-used ([basic.def.odr]) or needed for constant evaluation ([expr.const]).
TL;DR =default
in the class only declares a thing; if it's not used it's not defined.