Reputation: 2282
I am referring to this excellent blog post regarding the "Unforgettable Factory Registration Pattern": http://www.nirfriedman.com/2018/04/29/unforgettable-factory/
I've noticed that this stops working when the self-registering types are default constructible. In the example provided by the code, the self-registering types (Animal
base class) defines a constructor with an int
parameter. If I slightly modify the code to make Animal
become default constructible, the data map in the factory remains empty and objects of type Cat
and Dog
can no longer be constructed through the factory.
As far as I understand the issue lies in the fact that the Animal
class no longer calls the registerT
function. However, I fail to understand why that is and what modification(s) are necessary to make it work with default constructible classes.
Can somebody shed some light on this?
Useful:
Upvotes: 1
Views: 89
Reputation: 170074
The int
argument is a red herring. When changing the argument list you modified
Dog(int x) : m_x(x) {}
to be
Dog() = default;
From a user-provided constructor, to a defaulted one.
In effect, this means the compiler (I checked Clang and GCC) doesn't emit a function definition for Dog::Dog()
, so it doesn't odr-use Animal::Registrar<Dog>::Registrar<Dog>()
, which means its definition isn't instantiated (member function bodies only are only instantiated when odr-used). And so we never odr-use its registered
static data member.
If the constructor is defaulted, then we never actually end up registering the factory function into the map. And indeed, after it becomes user-provided again, things start to work.
I am however unable to understand why that makes a difference. The user-provided constructor is still an inline member function. And inline function definitions are tied to odr-usage too. But perhaps that should be the subject of another question.
Upvotes: 1