Search code examples
c++classtemplatesradixderived

C++: Cannot convert argument 1 from Child non-template class to Parent template class


I know there is a lot of these "cannot convert argument" questions here, but I promise I looked around a lot and I think my particular case hasn't been asked yet, plus I have tried debugging this for quite a few hours but can't seem to get it.

Basically, I am creating a Component system for a 2D game engine. I have separated my logic into two parts: Component and ComponentSystem. The Component class will store only data, while the ComponentSystem will update and manipulate that data accordingly.

The ComponentSystem base class is abstract with a template to specify which Component the system will be using. Here is the .h file:

// =================================================================================================
// == COMPONENT SYSTEM CLASS =======================================================================
// =================================================================================================
template <class T>
class ComponentSystem
{
public:
    // -- ctor & dtor
    ComponentSystem<T>();
    ~ComponentSystem<T>();

    // -- update components
    virtual void UpdateComponents(float dt) = 0;
    // -- populates the components of this systems
    virtual void PopulateFromCurrentLevel() = 0;
    // -- clears the components of this system
    virtual void ClearFromCurrentLevel() = 0;

protected:
    // -- actual list of components
    std::vector<T*> components;
};

I then also have a SpriteComponentSystem, which derives from ComponentSystem, but with the SpriteComponent as the template type:

class SpriteComponentSystem : public ComponentSystem<SpriteComponent>
{
public:
    SpriteComponentSystem();
    ~SpriteComponentSystem();
    virtual void UpdateComponents(float dt);
    virtual void PopulateFromCurrentLevel();
    virtual void ClearFromCurrentLevel();
};

Finally, in my Game class I am storing a vector of the base class, like so:

std::vector<ComponentSystem<Component*>*> systems;

However, when I try to push a SpriteComponentSystem* into systems, I get the following error:

C2664 - 'void std::vector<HSZGame::ComponentSystem<HSZGame::Component *> 
*,std::allocator<_Ty> >::push_back(_Ty &&)': cannot convert argument 1 from 
'HSZGame::SpriteComponentSystem *' to 
'HSZGame::ComponentSystem<HSZGame::Component *> *const &'  

I have tried implementing a specific cast from one object to the other, and also tried doing a dynamic_cast which worked for compile time but the object was then nullptrat runtime.

In case anyone is wondering, SpriteComponent does indeed inherit from Component, which is the base class. Thanks again for your help everyone!


Solution

  • First of all you are initializing a std::vector<ComponentSystem<Component*>*> that takes a ComponentSystem with a Component* template parameter. This means that your vector components that is contained within ComponentSystem is holding a pointer to a pointer to a Component. This might be an error on your part unless you actually mean to hold a pointer to a pointer. If you don't your vector should be initialized std::vector<ComponentSystem<Component>*>.

    Secondly it seems you would like to use runtime polymorphism so that your vector systems can hold not only ComponentSystem<Component> objects but also SpriteComponentSystem (AKA ComponentSystem<SpriteComponent> objects).

    Unfortunately the language does not allow this since templates are instantiated at compile time and each instantiation is its own type. The language views ComponentSystem<Component> and ComponentSystem<SpriteComponent> as separate types and hence the compiler is complaining.

    I think you would need to rethink this design philosophy.