私はこれをstd::functionとstd::bindで行いました。
ハンドラーのベクトルをunordered_mapに格納するこのEventManagerクラスを作成しました。このクラスは、イベントタイプ(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ではなく配列の配列を使用して高速化したいのですが、メンバー関数を格納する方法がよくわかりません。ポインタを作成し、呼び出されているクラスについて何も知らないコードから呼び出します。まつげの答えはとても面白いようです。