L'ho fatto con std :: function e std :: bind ..
Ho scritto questa classe EventManager che memorizza un vettore di gestori in un unordered_map che mappa i tipi di eventi (che sono solo const unsigned int, ne ho una grande enumerazione con ambito spazio dei nomi) a un vettore di gestori per quel tipo di evento.
Nella mia classe EventManagerTests, ho impostato un gestore di eventi, come questo:
auto delegate = std::bind(&EventManagerTests::OnKeyDown, this, std::placeholders::_1);
event_manager.AddEventListener(kEventKeyDown, delegate);
Ecco la funzione 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;
}
Ecco la definizione del tipo EventHandler:
typedef std::function<void(Event *)> EventHandler;
Quindi di nuovo in EventManagerTests :: RaiseEvent, faccio questo:
Engine::KeyDownEvent event(39);
event_manager.RaiseEvent(1, (Engine::Event*) & event);
Ecco il codice per 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);
}
);
}
}
Funziona. Ricevo la chiamata in EventManagerTests :: OnKeyDown. Devo eliminare i vettori al momento della pulizia, ma una volta fatto non ci sono perdite. La generazione di un evento richiede circa 5 microsecondi sul mio computer, che è circa il 2008. Non esattamente super veloce, ma. Abbastanza giusto finché lo so e non lo uso in codice ultra caldo.
Mi piacerebbe velocizzarlo eseguendo il rollio dei miei std :: function e std :: bind, e magari usando un array di array piuttosto che un unordered_map di vettori, ma non ho ancora capito come memorizzare una funzione membro pointer e chiamalo da codice che non sa nulla della classe chiamata. La risposta di Eyelash sembra molto interessante ..