mercredi 8 juillet 2020

templated function for registration of event handlers

I would like to create a function which will register an event handler. EventHandler is registered to listen for a particular eventType. Method will have a Type and a variable number of parameters required for concrete EventHandler construction. Each concrete event handler will be derived from the abstract class EventHandler.

/* E.g this is an abstract eventHandler */
class EventHandler
{
public:
  virtual ~EventHandler() {};
  virtual void OnMessage(const Message *msg) = 0;
};

/* this is an example of derived event handler */
class ServerEventHandler : public EventHandler
{
    int someVar1;
    int someVar2;
public:
  ServerEventHandler(int var1, var2): someVar1(var1), someVar2(var2) {}
  void OnMessage(const Message* msg)
  {
      std::cout << "ServerEventHandler"
  }
};

I would like to store event handlers in a vector sorted by their type. I know that the best data structure for this application would be std::multimap, however due to the nature of this problem I am only allowed to use a vector.

I can only think of wrapping eventHandler in another class Listener to be able to do it. Currently I am using a templated function registerHandler for that.

My gut feeling tells me that this is not an elegant way to do it. For example to be able to find a proper position where the new handler will be placed I will need to create a temporary listener which doesnt sound right to me. I am using templated function because I would like to do in place construction.

struct Listener
{
    int32_t eventType;
    std::unique_ptr<EventHandler> handle;
};

std::vector<Listener> listeners;

template<typename HandlerType, typename ...HandlerParametersType>
int registerHandler(int type, HandlerParametersType&&... handlerParams)
{
    Listener m_searchValue;
    m_searchValue.m_type = type;

    /* Listeners are sorted in the vector by their type */
    auto pos = std::lower_bound(m_listeners.begin(), m_listeners.end(), m_searchValue, [](const Listener& theirs, const Listener& my)
    {
        if (theirs.m_type < my.m_type)
            return true;
        else
            return false;
    }
    );

    pos = listeners.emplace(pos, type, std::move(std::make_unique<HandlerType>(std::forward<HandlerParametersType>(handlerParams)...)));
}

This is how I will call it

registerHandler<ServerEventHandler>(MESSAGE_TYPE_3, 4, 5);

Aucun commentaire:

Enregistrer un commentaire