Sam Bloomberg Sam Bloomberg - 1 month ago 7
C++ Question

Getting around the lack of templated virtual functions in C++

I'm not sure how best to phrase the question, but I'm not asking how to implement templated virtual functions per-se. I'm building an entity component system, and I have two important classes -

World
and
Entity
. World is actually an abstract class, and the implementation (let's call it
WorldImpl
) is a templated class that allows use of a custom allocator (one that can be used with
std::allocator_traits
).

Components are any data type which we can attach to entities. This is done by calling a templated function named
assign
on the entity.

Here's the problem: I'm trying to make the entity use the world's allocator when creating and initializing components. In a perfect world, you would call
Entity::assign<ComponentType>( ... )
which would ask the
WorldImpl
to create the component with whatever allocator is appropriate. There's a problem here, however - The entity has a pointer to
World
and templated virtual functions aren't possible to my knowledge.

Here's a bit more of an illustration that might make the issue more obvious:

class Entity
{
template<typename ComponentType>
void assign(/* ... */)
{
/* ... */
ComponentType* component = world->createComponent<ComponentType>(/* ... */);
/* ... */
}

World* world;
};

// This is the world interface.
class World
{
// This is the ideal, which isn't possible as it would require templated virtual functions.
template<typename ComponentType>
virtual ComponentType* createComponent(/* ... */) = 0;
};

template<typename Allocator>
class WorldImpl : public World
{
template<typename ComponentType> // again, not actually possible
virtual ComponentType* createComponent(/* ... */)
{
// do something with Allocator and ComponentType here
}
};


Seeing as the above code isn't actually possible, here's the real question: With a class hierarchy such as this, what black magic do I have to do in order for some function to be called with both the ComponentType and Allocator template parameters? This is the ultimate goal - a function called on some object with both template parameters available to it.

Answer

I'd say that Entities belong to a certain kind of world and make them templates with a World parameter. Then you can forget about all the inheritance and virtual and just implement worlds that fulfill the required interface, e.g.

template<typename World>
class Entity
{
  template<typename ComponentType>
  void assign(/* ... */)
  {
    /* ... */
    ComponentType* component = world.createComponent<ComponentType>(/* ... */);
    /* ... */
  }

  World world;
};

template<typename Allocator>
class WorldI
{
  template<typename ComponentType>
  ComponentType* createComponent(/* ... */)
  {
    // do something with Allocator and ComponentType here
  }
};
Comments