0

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.

Community
  • 1
  • 1
haxpor
  • 2,431
  • 3
  • 27
  • 46
  • 2
    `T*` is already a specific type once you instantiate the template, so I'm unclear why you need to check it. If you want `T*` to map to specific constant for the `int type` parameter, then you need some kind of type trait. – Stephen Lin Mar 03 '13 at 21:54
  • 1
    Can't your function be called with a type parameter, too? Like " template void popFreeObjectAndAddToActiveListForType()" ? Why have an int for types at all? – nvoigt Mar 03 '13 at 21:57
  • 1
    @haxpor what nvoight said – Stephen Lin Mar 03 '13 at 22:00
  • Firstly I came up with specific functions for each spawning type, and I need to have one generic function to cover all types to spawn. Anyway, at this stage I would like to remain functionality of popFreeObjectAndAddToActiveListForType() and its parameter as it is. At least doing this way (above) will reduce code. – haxpor Mar 03 '13 at 22:00
  • @haxpor I am not sure, but I think my answer below with type traits might be what you want..I could be wrong though. – Stephen Lin Mar 03 '13 at 22:03
  • Hey thanks guys, this triggers me about the design flaw. I have edited the question at the bottom. Anyway, I'm still seeking for solution for this kind of situation. I'm reading and trying answers now. – haxpor Mar 03 '13 at 22:12

2 Answers2

1

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.

masoud
  • 55,379
  • 16
  • 141
  • 208
  • I try to avoid using dynamic_cast, it requires too many if else-if. Also I'm not using C++11 right now so I cannot find is_same, but thanks for introduce it to me. – haxpor Mar 03 '13 at 22:24
  • @M.M. fyi, it doesn't really matter if `T` is a base class of `Zombie01` actually, dynamic_cast will [cross cast](http://stackoverflow.com/questions/5321664/checking-whether-a-cross-cast-could-possibly-work) any two polymorphic pointers. – Stephen Lin Mar 03 '13 at 22:34
  • @StephenLin: You're right. I assumed "multiple non-virtual derivation" isn't used for those objects. – masoud Mar 04 '13 at 06:22
1

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;
}
Community
  • 1
  • 1
Stephen Lin
  • 5,470
  • 26
  • 48
  • Thanks, I got several useful tidbits about C++ and this interesting type traits. However, I got linker error saying that "Undefined symbols for architecture armv7: "Zombie01* ObjectSpawner::spawnEnemy(ObjectSpawner::SpawnDirection)", referenced from: ... ". I believe it's something to do with where to declare or its own syntax. I took a look at [boost](http://www.boost.org/doc/libs/1_37_0/boost/type_traits/detail/is_mem_fun_pointer_impl.hpp) and despite not exactly what we're doing here, but I can't find any mis-steps. – haxpor Mar 04 '13 at 04:53
  • I defined generic template in header file, and the specialization template in the implement file as I got a compile error if I put it in header file. I also take a look at this [link](http://accu.org/index.php/journals/442#boost) as well, but not work so far. – haxpor Mar 04 '13 at 04:56
  • did you put all the above in the header file? [(helpful info)](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file)...you can do explicit instantiation too as an alternative, but that's a bit less standard – Stephen Lin Mar 04 '13 at 04:56
  • I separated it, see [here](https://gist.github.com/haxpor/5080097). It's link error, no compile error, it cannot seem to find a reference spawnEnemy() to work with. – haxpor Mar 04 '13 at 05:11
  • yeah, that needs to be in the header, why does that error? is it because `Zombie01` is undefined when the template is defined? – Stephen Lin Mar 04 '13 at 05:15
  • I forgot to mention that I can't put it there in header file, if I put it there it shows error "Explicit specialization of `EnemyTraits` in class scope". – haxpor Mar 04 '13 at 05:17
  • 1
    let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/25490/discussion-between-stephen-lin-and-haxpor) – Stephen Lin Mar 04 '13 at 05:18