Search code examples
c++templatesoverloadingvirtual

Overloading when inheriting from two differently-templated copies of the same class


I'm writing an input-handling system for a game that I'd like to make extensible to arbitrary event types. I'd like to design an interface-like specification that allows me to enforce that certain objects are expected to handle certain events; for instance via something like class Player : public EventHandler<KeyboardEvent>. My proposed design for such a thing is as follows.

template <class T>
class EventHandler {
public:
    void handleEvent(T event) { doHandleEvent(event); };
private:
    virtual void doHandleEvent(T event) {};
};

class InputHandler : public EventHandler<Action>, public EventHandler<CursorEvent> {};

However, at the point where I call InputHandler::handle(), the above produces the following errors. It appears that handleEvent() for both templated versions of EventHandler is treated as the same function. I was under the impression that since the two versions of handleEvent have different argument types, the result should be as if InputHandler had one overloaded function with the two possible argument types.

Why doesn't C++ allow this, and what are some better alternatives to what I'm trying to do? I suspect the above may not be good practice.

/Users/smichaels/Projects/danmaku/src/SDL/Input.cpp:35:34: error: member 'handleEvent' found in multiple base classes
      of different types
                if (act) handler.handleEvent(act.get());
                                 ^
/Users/smichaels/Projects/danmaku/src/SDL/../Input/InputHandler.hpp:15:14: note: member found by ambiguous name lookup
        void handleEvent(T event) { doHandleEvent(event); };
             ^
/Users/smichaels/Projects/danmaku/src/SDL/../Input/InputHandler.hpp:15:14: note: member found by ambiguous name lookup

Solution

  • class InputHandler :
      public EventHandler<Action>,
      public EventHandler<CursorEvent>
    {
    public:
      using EventHandler<Action>::handleEvent;
      using EventHandler<CursorEvent>::handleEvent;
    };
    

    in you can instead write:

    template<class...Bases>
    struct ManyHandler:Bases...{
      using Bases::handleEvent...;
    };
    template<class...Events>
    using EventsHandler=ManyHandler< EvendHandler<Events>...>;
    

    then

    class InputHandler : public EventsHandler<Actions, CursorEvent >{};
    

    and if you also have

    class OutputHandler : public EventsHandler< Messages, Sounds >{};
    

    we can write

    class IoHandler : public ManyHandler< InputHandler, OutputHandler > {};