I have class World
which manages creation of object... After creation it calls afterCreation
method and I the created object is user-defined type derived from Entity (eg. MyEntity
), I want to call addEntity
. I the object was something else, I want to do nothing.
addEntity
must be called with appropriate T
, because it generates unique IDs for every derived class etc.
Here is my solution:
template <int v>
struct ToType
{
enum { value = v };
};
template <typename T>
void World::afterCreation(T * t)
{
afterCreation(t, ToType<std::is_base_of<Entity, T>::value>());
}
template <typename T>
void World::afterCreation(T * t, ToType<true>)
{
addEntity(t); //here I cant pass Entity *, I need the real type, eg. MyEntity
}
template <typename T>
void World::afterCreation(T * t, ToType<false>)
{
}
My question is - Can in be done better way?
How can I simulate following code without ToType
or similar?
template <typename T>
void afterCreation(){/*generic impl*/}
template <typename T where T is derived from Entity>
void afterCreation(){/*some specific stuff*/}
It is not going to make it much better, but you can remove one level of indirection by using SFINAE:
template <typename T>
typename std::enable_if< std::is_base_of<Entity, T>::value >::type
World::afterCreation(T * t)
{
// Derived from Entity
}
template <typename T>
typename std::enable_if< !std::is_base_of<Entity, T>::value >::type
World::afterCreation(T * t)
{
// generic
}
How does this work? When the compiler finds the call to afterCreation
it tries to determine which of the overloads is best, and for that it matches the types and tries to perform the substitution. In both cases, the matched type (from the arguments) and apply the substitution to the whole expression. The enable_if
template contains an inner type type
if the value passed as the first argument is true
or else it does not contain such type. During the substitution of the types, one of the overloads will yield an invalid function signature (the one for which the condition is false) and will be dropped from the set of candidates.
You can do this with polymorphic pointers:
template <typename T>
void afterCreation(T* x) {
T* entity = dynamic_cast<Entity*> x;
if (!entity) {
// ... generic implementation
} else {
// ... entity implementation, use "entity"
}
}
Though this might not be the best solution since this has a (tiny) run-time overhead. A very smart compiler might remove this overhead through static analysis but I doubt compilers will pick this up.
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