これをstd :: functionとstd :: bindで行いました。
ハンドラーのベクターをイベントタイプ(const unsigned intであり、名前空間スコープの大きな列挙型)をそのイベントタイプのハンドラーのベクターにマップするunordered_mapにハンドラーのベクターを格納するこのEventManagerクラスを書きました。
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ではなく配列の配列を使用しますが、メンバー関数を格納する方法がまだわかりませんポインタがあり、呼び出されているクラスについて何も知らないコードから呼び出します。まつげの答えは非常に興味深いようです。