24

これがコールバックを書くための受け入れられたアプローチであるかどうか疑問に思いました:

コールバックの保存:

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
});

私の最大の質問は、コールバックを値で渡すことに関するものです。これは有効なアプローチですか?

4

3 に答える 3

16

これは、イベントハンドラーを格納するための完全に有効なアプローチです。

ただし、コールバックを追加するための関数のシグネチャに関する詳細をいくつか指摘したいと思います。あなたはそれを値で渡すか参照で渡すかについて心配します。あなたの例では、現在次のものがあります。

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);

簡単にするために、値を渡す方法を選択するときはいつでも、一般的に次のガイドラインに従うことができます。

  • 渡された実際のオブジェクトを変更せずに、送信された値のコピーが必要な場合、または変更する予定の場合:値渡し。
  • 送信された値を変更する予定であり、これらの変更が実際に渡されるオブジェクトに影響を与えるようにする場合:参照渡し。
  • 渡されたオブジェクトを変更したくないが、コピーを避けることが有益であると信じている場合:const参照で渡します。
  • 値、参照、または定数参照によってパラメーターを取得し、入力パラメーターが一時的なものであるという知識を使用して達成できる貴重な最適化があると信じる場合:右辺値参照も渡すことができます。
于 2013-03-27T06:47:38.050 に答える
1

はい。関数は、生の関数ポインターまたは軽量クラスのいずれかであり、コピーコンストラクターには副作用がないため、コピーは元のオブジェクトとして機能する必要があるため、このアプローチは完全に問題ありません。しかし、オブジェクトを値で渡してから元のコンテナーに移動する理由は、参照を渡してからコンテナーにコピーし、r値の参照を受け入れるオーバーロードされた関数を使用できることです(それほど重要ではありません)。

于 2013-03-27T06:06:31.003 に答える
0

私はほぼ同じ問題を抱えていました。モニターがいくつ存在し、どこにあるのか知りたかったのです。

少なくとも私はあきらめて、短い構造を書きました。良くありませんが、私は情報だけが欲しかったのです。

私が試したラムダでさえ、ラムダの定義のためにチャンスはありません...固定されたAddrではなく、2番目はCALLBACKとして構築できませんでした...

#include <WinUser.h>
#include <vector>
using namespace std;

struct _sMonitors{
        struct DispInfo {
            HMONITOR    hMon;
    //      HDC         dcMon;      // Everytime NULL (What ever!)
            RECT        pRcMon;
        };
        list< DispInfo> List;
        _sMonitors() {
            EnumDisplayMonitors(0, 0, Func, (LPARAM)this);
        }
        BOOL static CALLBACK Func(HMONITOR hMon, HDC dcMon, LPRECT pRcMon, LPARAM lParam){
            auto& Struct = *((_sMonitors*)lParam);
            Struct.List.push_back({ hMon,*pRcMon });
            return 1; 
        }
};
_sMonitors Monitors;

私の言語で言うように!Mann ging mir das auf den Sack .. ..

于 2020-09-29T15:36:41.983 に答える