Reputation: 2601
I have the following template function defined at the header file.
template <class T> T* spawnEnemy(SpawnDirection dir);
My intention is to create a generic spawning function that accepts type of enemy as a template parameter and return the spawned object from the function.
The following is incorrect implementation but I use it to express what I want to achieve.
template <class T> T* ObjectSpawner::spawnEnemy(SpawnDirection dir)
{
if(_enemiesPool->isAnyFreeObjects())
{
T* enemy = NULL;
if(typeof(T*) == Zombie01) // This line is INCORRECT
enemy = dynamic_cast<T*>(_enemiesPool->popFreeObjectAndAddToActiveListForType(ZOMBIE));
else if ...
return enemy;
}
else
return NULL;
}
That is I need to be able to do type checking from T, so I can appropriately call function
popFreeObjectAndAddToActiveListForType(int type)
with correct value as its input.
So how can I do type checking in situation like this within template function?
EDIT: After got a suggestion from stephen lin and nvoigt, then I see that this design has a flaw but it's because I top it up from what I already. The easier is to let function have another type parameter and not involve with template but do need to cast to specific type later. Anyway, it's good to know a solution for this situation.
Upvotes: 0
Views: 206
Reputation: 5540
I think you want something like this (using type traits):
The following section of code must be put outside of the class section.
template <typename T>
struct EnemyTraits { };
template <>
struct EnemyTraits<Zombie01> { static const int pop_type = ZOMBIE; };
template <>
struct EnemyTraits<Vampire01> { static const int pop_type = VAMPIRE; };
The following function should be defined in header file as suggested in this.
template <typename T> T* ObjectSpawner::spawnEnemy(SpawnDirection dir)
{
if(_enemiesPool->isAnyFreeObjects())
{
const int pop_type = EnemyTraits<T>::pop_type;
return dynamic_cast<T*>(_enemiesPool->popFreeObjectAndAddToActiveListForType(pop_type));
}
else
return NULL;
}
Upvotes: 1
Reputation: 56479
One possibility is using dynamic_cast
, if T
is base class of Zombie01
:
T *enemy = dynamic_cast<Zombie01*>(x);
if (!enemy)
{
// x can not cast to Zombie01
// do something else
}
However, it is recommend to minimizing the usage of dynamic_cast
Another idea is using std::is_same
:
If T and U name the same type with the same const-volatile qualifications, provides the member constant value equal to true. Otherwise value is false.
However, I'm trying to use Scott Meyers's hint from Effective C++:
"Anytime you find yourself writing code of the form "if the object is of type T1, then do something, but if it's of type T2, then do something else," slap yourself.
Upvotes: 1