For the sake of a demonstration imagine that I have some animal classes, each derived from an 'animal' class, each 'knowing' what type they are, and each having some sort of unique ability:
enum class animal_type { antelope, bear, cat };
class animal
{
};
class antelope : public animal
{
public:
static const animal_type type = animal_type::antelope;
void run() { std::cout << "antelope runs\n"; };
};
class bear : public animal
{
public:
static const animal_type type = animal_type::bear;
void roar() { std::cout << "bear roars\n"; };
};
class cat : public animal
{
public:
static const animal_type type = animal_type::cat;
void meow() { std::cout << "cat meows\n"; };
};
Now, I want to be able to retrieve animals based on their type:
class animal_getter
{
public:
animal& get(animal_type t)
{
static antelope s_antelope;
static bear s_bear;
static cat s_cat;
switch (t)
{
case animal_type::antelope:
return s_antelope;
case animal_type::bear:
return s_bear;
case animal_type::cat:
return s_cat;
}
}
};
And finally, it would be nice to get the actual type of animal back, to make the calling syntax nicer:
template<typename T>
T& get()
{
return static_cast<T&>(get(T::type));
}
Now I can write something like this:
animal_getter ag;
ag.get<antelope>().run();
rather than the wordier:
animal_getter ag;
static_cast<antelope&>(ag.get(animal_type::antelope)).run();
I hope there's nothing too unreasonable about that. But now I want to be able to unit test getting an animal, so ideally it will be possible to fake the animal_getter class (imagine the actual implementation accesses a database or something which you don't want in a unit test, hence the fake). So it would be nice to define an interface for 'animal getter' classes, and then create a fake that implements the interface. And here's the problem, can this interface be written? This isn't going to compile:
struct IAnimalGetter
{
virtual template<typename T> T& get() = 0;
};
Is it possible to rescue this idea or can template functions never be declared a virtual for the purpose of defining an interface that includes them?
If the idea is a non-starter, at what point did this start to go wrong? Was it when the template function was written which does its own casting? Should I have stopped at something which returns an animal object and then have the caller be responsible for the cast?