Implementing a simple toy eventloop in C++, I bumped into a problem. I have an interface (abstract class) Event
which is implemented by different types of events (keyboard, asynchronous calls, ...). In my example SomeEvent
is the implementation of Event.
enum class EventType {
SOME_EVENT = 0,
};
class Event {
public:
virtual ~Event() {}
virtual EventType get_event_type() = 0;
};
class SomeEvent: public Event {
public:
SomeEvent(): m_event_type(EventType::SOME_EVENT) {}
void bar() { std::cout << "hello" << std::endl; }
EventType get_event_type() { return this->m_event_type; }
public:
EventType m_event_type;
};
An EventHandler
is a lambda that takes an Event
, does something with it and returns nothing. I have a map of EventHandler
associated to an event type. (The map points to an EventHandler
in this MWE but in my original implementation it points to a vector of course)
typedef std::function<void(std::unique_ptr<Event>)> EventHandler;
std::map<EventType, EventHandler> event_handlers;
template <class T>
void add_event_handler(
EventType event_type,
const std::function<void(std::unique_ptr<T>)> &event_handler) {
event_handlers[event_type] = event_handler; // Does not compile
}
When I inject an event with inject_event
, I just fetch the event handler in the map and call it with the event as argument.
void inject_event(std::unique_ptr<Event> event) {
event_handlers[event->get_event_type()](std::move(event));
}
The problem comes from the genericity of this map. It supposed to hold a handler that takes an Event
but I guess there is no inheritance link between a lambda taking an interface and a lambda taking an implementation of that interface, so it fails because it can't assign a std::function<void(SomeEvent)>
to a variable of type ``std::function`.
I've been scratching my head over this and my C++ is rusty AND not up to date at all. How would you go about it? Is there a pattern or a functionality in the language that would allow me to specify a lambda in a generic way? Tried using auto
in EventHandler
definition but it does not seem to be allowed.