Hice esto con std :: function y std :: bind ..
Escribí esta clase EventManager que almacena un vector de controladores en un mapa unordered_map que asigna tipos de eventos (que son solo const unsigned int, tengo una gran enumeración de espacios de nombres de ellos) a un vector de controladores para ese tipo de evento.
En mi clase EventManagerTests, configuré un controlador de eventos, como este:
auto delegate = std::bind(&EventManagerTests::OnKeyDown, this, std::placeholders::_1);
event_manager.AddEventListener(kEventKeyDown, delegate);
Aquí está la función AddEventListener:
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;
}
Aquí está la definición de tipo EventHandler:
typedef std::function<void(Event *)> EventHandler;
Luego, de vuelta en EventManagerTests :: RaiseEvent, hago esto:
Engine::KeyDownEvent event(39);
event_manager.RaiseEvent(1, (Engine::Event*) & event);
Aquí está el código para 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);
}
);
}
}
Esto funciona. Recibo la llamada en EventManagerTests :: OnKeyDown. Tengo que eliminar los vectores en tiempo de limpieza, pero una vez que lo hago no hay fugas. Generar un evento toma alrededor de 5 microsegundos en mi computadora, que es alrededor de 2008. No exactamente súper rápido, pero. Bastante justo siempre que sepa eso y no lo use en código ultra caliente.
Me gustaría acelerarlo rodando mi propia std :: function y std :: bind, y tal vez usando una matriz de matrices en lugar de un unordered_map de vectores, pero no he descubierto cómo almacenar una función miembro puntero y llamarlo desde un código que no sabe nada sobre la clase que se llama. La respuesta de Eyelash parece muy interesante.