4

私はtypedefを持っています:

typedef S32(iMyDataClass1::*getDataFunction_t)(void);

およびタイプ:

struct functionMap_t {
    std::vector<getDataFunction_t> pDataFunctionTable;
    struct dataRequestor_t dataRequestor;
};

次に、メンバー変数があります。

functionMap_t FnMap1;

次に、メンバー初期化子リストに設定します。

myClass::myClass() : FnMap1({ 
 {
     &iMyDataClass1::getData1,
     &iMyDataClass1::getData2,
     &iMyDataClass1::getData3
   },
   dataRequestor1
 })

次に、コンストラクターで使用します。

addNewFnMap(FnMap1);

これはすべてうまくいきます。残念ながら、別のクラスへの関数ポインターに拡張することはできませんgetDataFunction_tiMyDataClass1

テンプレートを使用してみましたが、回避できない問題に遭遇しました。を使用しようとしてstd::functionいます。つまり、元の typedef を (私が思うに) に変更します。

typedef std::function<S32(void)> getDataFunction_t;

この状況で初期化リストを設定する正しい方法は何ですか? ここ使うstd::bind

更新: これは、新しいイニシャライザ リストでの私の試みです。これが正しいかどうかはわかりませんが、これはこの質問を投稿する直前に私が持っていたものです:

{ 
  {
    (std::bind(&iMyDataClass1::getData1, functionToFetchCorrectObject())),
    (std::bind(&iMyDataClass1::getData2, functionToFetchCorrectObject())),
    (std::bind(&iMyDataClass1::getData3, functionToFetchCorrectObject()))
  },
  PGN65370
}
4

2 に答える 2

3

ラムダ式を使用できます。ただし、署名を のままにしたい場合はstd::function<S32(void)>、オブジェクトをキャプチャする必要があります。

myClass::myClass() : FnMap1({
  {
     [this](){ return getData1(); },
     [this](){ return getData2(); },
     [this](){ return getData3(); },
  },
  dataRequestor1
})

これを行いたくない場合は、署名を変更して、thisポインターをパラメーターとしてコールバックに渡すことができます。しかし、Barry がコメントで指摘しているように、これでは異なるクラスへのコールバックを同じ .xml に入れることはできませんvector。ラムダ内のポインターを使用できますがreinterpret_cast、見苦しく危険であることに加えて、呼び出し元はどのポインターを渡すかをどのように知るのでしょうか?

于 2015-05-11T21:26:37.810 に答える
2

さまざまなクラスで動作させたい場合は、必要な署名を付けて callable を単純に保存できます。

struct functionMap_t {
  std::vector<std::function<S32(void)>> pDataFunctionTable;
  struct dataRequestor_t dataRequestor;
};

次に、私がおそらく行うことは、正しいシグネチャを持つ std::functions を返す高階関数をクラスに与えることです。

std::function<S32(void)> iMyDataClass1::getData1Getter() {
  auto f = [this] () {return this->getData1()};
  return f;
}

これで、かなり簡単に初期化できます。

iMyDataClass1 o;
...

FnMap1({o.getData1Getter(), ..., dataRequestor1});

このコードは注意深くチェックされておらず、構文エラーが含まれていると確信しています。しかし、それはあなたにそれの要点を与えるべきです。主な考え方は、特定のオブジェクトにアタッチされているかどうかに関係なく関数を操作する場合は、関数 (実際にはクロージャー自体) を操作する必要があるということです。このような方法で関数を操作すると、高階関数を使用する設計が動機付けられ、あるコンテキストから関数が返され、別のコンテキストに渡されます。

編集: 私は最近、C++11 の Observer パターンについて誰かとデザインの会話をしました。これと非常に似たようなことをすることをお勧めします。ポリモーフィズムの使用を避け、物事を汎用的かつ分離したままにし、継承階層の汚染を回避することは非常に良いことです。

于 2015-05-11T21:47:17.603 に答える