I was wondering whether a design pattern or idiom exists to automatically register a class type. Or simpler, can I force a method to get called on a class by simply extending a base class?
For example, say I have a base class Animal
and extending classes Tiger
and Dog
, and I have a helper function that prints out all classes that extend Animal
.
So I could have something like:
struct AnimalManager
{
static std::vector<std::string> names;
static void registerAnimal(std::string name) {
//if not already registered
names.push_back(name); }
};
struct Animal
{
virtual std::string name() = 0;
void registerAnimal() { AnimalManager::registerAnimal(name()); }
};
struct Tiger : Animal
{
virtual std::string name() { return "Tiger"; }
};
So basically I would do:
Tiger t;
t.registerAnimal();
This could be worked into a static
function as well. Is there any pattern (like a curiously recursive template) or something like that that can help me achieve this without explicitly having to call the registerAnimal
method.
I want my class Animal
to be extendible in the future and others might forget to call register
, I'm looking for ways to prevent that besides documenting this (which I will anyway).
PS This is just an example, I'm not actually implementing animals.
The register function simply returns its internal function, which in turn is executed immediately with the wrapped class type as its input. The internal function is the one that actually registers the class, and then returns the class type that will be added to the current namespace by the python interpreter.
// A class cannot have non-static object(s) of self type. If a non-static object is member then declaration of class is incomplete and compiler has no way to find out size of the objects of the class.
Class registration is a helpful pattern for building modular Python programs. Metaclasses let you run registration code automatically each time your base class is subclassed in a program. Using metaclasses for class registration avoids errors by ensuring that you never miss a registration call.
You can indeed do this using the curiously recursive template idiom. It requires nothing from whoever is extending the class that can't be enforced by the compiler:
template<class T>
struct Animal
{
Animal()
{
reg; //force specialization
}
virtual std::string name() = 0;
static bool reg;
static bool init()
{
T t;
AnimalManager::registerAnimal(t.name());
return true;
}
};
template<class T>
bool Animal<T>::reg = Animal<T>::init();
struct Tiger : Animal<Tiger>
{
virtual std::string name() { return "Tiger"; }
};
In this code, you can only extend Animal
if you specialize it. The constructor forces the static
member reg
to be initialized, which in turn calls the register method.
EDIT: As pointed out by @David Hammen in the comments, you won't be able to have a collection of Animal
objects. However, this can easily be solved by having a non-template class from which the template inherits and use that as a base class, and only use the template for extending.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With