を呼び出すことを定義する方法がわかりません。さもなければ、どのようにパラメータとして渡すべきか、あるいはどのような型を出力として受け取るべきかを知ることができますか?コールバック署名が知られており、固定されている場合は、上記の持っているように、例えばint(int,int,int)
のために、あなたはこのような工事を使用することができます。
class MyClass {
std::function<int(int,int,int)> callback;
public:
int run() {
return callback(1,2,3); // or whatever
}
template <typename Class>
void SetCallback (Class& o, int (Class::*m) (int,int,int)) {
callback = [&o,m] (int a, int b, int c) { return (o.*m)(a,b,c); };
}
template <typename Class>
void SetCallback (Class const& o, int (Class::*m) (int,int,int) const) {
callback = [&o,m] (int a, int b, int c) { return (o.*m)(a,b,c); };
}
};
MyClass
作品の上記の実装は次のよう:callback
は当初、未定義の関数オブジェクトです、 3つのint
があり、int
を返します。 SetCallback
は、コールバックを実行するオブジェクトo
と、callback
の署名に準拠するオブジェクトのメソッドm
の2つのパラメータをとります。それはo
のタイプが何であるか気にしません。タイプ消去のおかげで、MyClass
は実際に何を呼んでいるのかを知る必要はありません。
const
と非const
についてそれぞれ1つずつ、SetCallback
の2つのバージョンに特に注意してください。実際には、volatile
とconst volatile
のオーバーロードも記述する必要がありますが、それはconst
よりもはるかに稀です。将来、例外仕様とトランザクションが型システムの一部になると、noexcept
と同期についても注意する必要があります。その結果、タイプのコンビナトリアルな爆発は、非常に巧妙な言語サポートなしでは効果的に処理することが難しくなります。しかし、この例では、そのような種類のコードがどのように記述されるのかを示しています。
実装は醜いようですが、実際にはきれいなインターフェイスが提供されます。上記のコードは、署名int(int,int,int)
と方法を持っている任意のタイプで動作します
MyClass test;
Foo foo;
foo.d = 4;
test.SetCallback (foo, &Foo::the_func);
int result = test.run(); // result = 10
:Foo
与えられたあなたは上記の書いたように、あなたはこのようなMyClass
のコールバック機能を使用します。 run
に電話する前にSetCallback
に電話する必要があります。コールバックがまだ定義されていないため、std::bad_function_call
例外が発生します。
仮想クラスを作成して回避策を作成しました。 MyClassはそれについて知っています、Fooはそれを実装しています。しかし私は私が尋ねたものに近い答えをしたいと思います –
私たちは 'std :: function'と' std :: bind'を持っています。 –