これがコールバックを書くための受け入れられたアプローチになるかどうか私は思っていました:
コールバックの保存:
struct EventHolder {
std::function<void()> Callback;
EventTypes::EventType Type;
};
std::vector<Events::EventHolder> EventCallbacks;
メソッド定義:
void On(EventType OnEventType,std::function<void()>&& Callback)
{
Events::EventHolder NewEvent;
NewEvent.Callback=std::move(Callback);
NewEvent.Type=OnEventType;
EventCallbacks.Push_back(std::move(NewEvent));
}
バインディングイベント:
Button->On(EventType::Click,[]{
// ... callback body
});
私の最大の質問は、値によってコールバックを渡すことです。これは有効なアプローチですか?
これは、イベントハンドラーを格納するための完全に有効なアプローチです。
ただし、コールバックを追加するための関数のシグネチャに関するいくつかの詳細を指摘したいと思います。値で渡すか参照で渡すかを心配します。あなたの例では、あなたは現在持っています:
void On(EventType OnEventType,std::function<void()>&& Callback)
これを右辺値にのみバインドする限り、これは良いことです。ただし、許可しない特別な理由がない限り、必要に応じて、値または左辺値参照でパラメーターを受け入れ、右辺値参照バージョンを補足として追加するメソッドを常に使用することをお勧めします。
左辺値参照を受け取るメソッドがないということは、次のような場合、コードは現在コンパイルに失敗することを意味します。
std::function<void()> func([](){/*something clever*/});
// Do something necessary with func, perhaps logging or debug prints.
Button->On(EventType::Click, func);
簡単にするために、値を渡す方法を選択するときはいつでも、一般的に次のガイドラインに従うだけで済みます。
はい。関数は、生の関数ポインターまたは軽量クラスのいずれかであり、コピーコンストラクターには副作用がないため、コピーは元のオブジェクトとして機能する必要があるため、このアプローチは完全に問題ありません。しかし、オブジェクトを値で渡し、それを元のコンテナーに移動する理由は、参照を渡し、それをコンテナーにコピーして、r値の参照を受け入れるオーバーロードされた関数がある場合です(それほど重要ではありません)。