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.