Я сделал это с помощью std :: function и std :: bind ..
Я написал этот класс EventManager, который хранит вектор обработчиков в unordered_map, который сопоставляет типы событий (которые являются просто const unsigned int, у меня их большое перечисление в области имен) на вектор обработчиков для этого типа события.
В моем классе EventManagerTests я настроил обработчик событий, например:
auto delegate = std::bind(&EventManagerTests::OnKeyDown, this, std::placeholders::_1);
event_manager.AddEventListener(kEventKeyDown, delegate);
Вот функция 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;
}
Вот определение типа EventHandler:
typedef std::function<void(Event *)> EventHandler;
Затем снова в EventManagerTests :: RaiseEvent я делаю следующее:
Engine::KeyDownEvent event(39);
event_manager.RaiseEvent(1, (Engine::Event*) & event);
Вот код для 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);
}
);
}
}
Это работает. Я получаю вызов в EventManagerTests :: OnKeyDown. Мне нужно удалить векторы, наступает время очистки, но как только я это сделаю, утечек не будет. Создание события на моем компьютере занимает около 5 микросекунд, это примерно в 2008 году. Не совсем быстро, но. Достаточно справедливо, если я знаю это и не использую это в сверхгорячем коде.
Я хотел бы ускорить его, свернув свои собственные std :: function и std :: bind, и, возможно, используя массив массивов, а не unordered_map векторов, но я не совсем понял, как сохранить функцию-член указатель и вызовите его из кода, который ничего не знает о вызываемом классе. Ответ Ресницы выглядит очень интересно ..