I did this with std::function and std::bind..
I wrote this EventManager class that stores a vector of handlers in an unordered_map that maps event types (which are just const unsigned int, I have a big namespace-scoped enum of them) to a vector of handlers for that event type.
In my EventManagerTests class, I set up an event handler, like this:
auto delegate = std::bind(&EventManagerTests::OnKeyDown, this, std::placeholders::_1); event_manager.AddEventListener(kEventKeyDown, delegate);
Here's the AddEventListener function:
std::vector<EventHandler>::iterator EventManager::AddEventListener(EventType _event_type, EventHandler _handler) { if (listeners_.count(_event_type) == 0) { listeners_.emplace(_event_type, new std::vector<EventHandler>()); } std::vector<EventHandler>::iterator it = listeners_[_event_type]->end(); listeners_[_event_type]->push_back(_handler); return it; }
Here's the EventHandler type definition:
typedef std::function<void(Event *)> EventHandler;
Then back in EventManagerTests::RaiseEvent, I do this:
Engine::KeyDownEvent event(39); event_manager.RaiseEvent(1, (Engine::Event*) & event);
Here's the code for EventManager::RaiseEvent:
void EventManager::RaiseEvent(EventType _event_type, Event * _event) { if (listeners_.count(_event_type) > 0) { std::vector<EventHandler> * vec = listeners_[_event_type]; std::for_each( begin(*vec), end(*vec), [_event](EventHandler handler) mutable { (handler)(_event); } ); } }
This works. I get the call in EventManagerTests::OnKeyDown. I have to delete the vectors come clean up time, but once I do that there are no leaks. Raising an event takes about 5 microseconds on my computer, which is circa 2008. Not exactly super fast, but. Fair enough as long as I know that and I don't use it in ultra hot code.
I'd like to speed it up by rolling my own std::function and std::bind, and maybe using an array of arrays rather than an unordered_map of vectors, but I haven't quite figured out how to store a member function pointer and call it from code that knows nothing about the class being called. Eyelash's answer looks Very Interesting..
Dog dog;) is more likely what you want.