#include <functional>
#include <iostream>
#include <map>
#include <memory>

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;
};


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;
}

void insert_event(std::unique_ptr<Event> event) {
  event_handlers[event->get_event_type()](std::move(event));
}

int main(int argc, char **argv) {
  add_event_handler<SomeEvent>(EventType::SOME_EVENT, [](auto b) { b->bar(); });
  // later...
  insert_event(std::make_unique<SomeEvent>());
}
