I'm implementing the unforgettable factory. Everything works fine but one thing: The classes are not registered, sometimes.
I think the crucial part is the Registrar::registered
member. If it is used, "The really fun part" calls the registerT
function which registers the class.
In my toy example, the class is not registered unless either
Animal
), which is overridden in the registered class and implemented in cpp-file. Inline implementation does not work (unlike inline ctor).Did I make a mistake or did the author miss something? In my real-world application, some classes are registered and some are not and I cannot spot the difference (all classes satisfy (1.)), that's why I must deepen my understanding.
My question is: Under which circumstances exactly is registerT
called? In other words: When is the constructor of Registrar
instantiated?
Where should I put the (void) registered;
such that it is always instantiated?
(*) to make constructor inheritance work, I made the constructors of Factory
and Factory<...>::Registrar
public
Edit: this question pointed me to the unforgettable factory blog post. This is not a duplicate. The author of that question apparently only forgot to add "The really fun part" and the crucial almost-empty-constructor. I didn't forget them. I want to know why this crucial almost-empty-constructor is not instantiated although it is there.
Edit: The solution was not to use the proposed pattern. It does not seem to be fit for production code, see the relevant issue.
[basic.start.dynamic]/3 A non-initialization odr-use is an odr-use (6.2) not caused directly or indirectly by the initialization of a non-local static or thread storage duration variable.
[basic.start.dynamic]/4 It is implementation-defined whether the dynamic initialization of a non-local non-inline variable with static storage duration is sequenced before the first statement of main or is deferred. If it is deferred, it strongly happens before any non-initialization odr-use of any non-inline function or non-inline variable defined in the same translation unit as the variable to be initialized.
This is what causes this and similar self-registration schemes to fail. There's a translation unit containing definitions of entities that are not referenced elsewhere in the program, but only by the initializer of a static variable defined in that same translation unit. The implementation may choose to defer the initialization of that static variable until anything in its translation unit is odr-used - which is never.