実装と短いテスト/デモをここに投稿しました: http://ideone.com/CNJDi
私は、これまで見てきた他のものとは大きく異なる C++ Delegates へのアプローチを思いつきました。私が特に解決したい問題は、特定のインスタンスが a) メンバー fn ptr+オブジェクト ptr または b) 非メンバー fn ptr のいずれかである、統一された関数ポインター ソリューションを持つことです。デリゲートを初期化して他のコードに渡すと、デリゲートは、それがどのタイプのオブジェクトから来たのかさえ知らなくても、動的に呼び出すことができます (通常、メンバー関数ポインターは、それが来たクラスを静的に参照することによってのみ呼び出すことができます. Boo !)。理論上は容易に可能ですが、C++ ではこのようなことを実行するのは非常に困難です。だから私はそれを機能させるために言語をひねりました。
私の実装の主な欠点は、メンバー関数ポインターのキャスト/呼び出しが無効なため、技術的に「標準に準拠」していないことです (少なくとも、標準がここで私を保護していないことは 95% 確信しています...)。しかし、私がテストしたコンパイラ (Visual Studio 2012 を含む) では動作します。また、メンバー関数がコンパイラによって簡単な方法で実装されている場合、それが「機能する傾向がある」ことは明らかだと思います。
私は他のいくつかの実装を見ましたが、私にはそれらが非常に複雑で使いにくいように見えました。メンバー関数を呼び出すスタブ関数を生成するためにビルド ツールに依存するものさえありましたが、私のものはマクロとテンプレートのみに依存していました。適切なデリゲートがないことは C++ の主な欠点だと思いますが、「この回避策が嫌いではない」ことがわかりました。実際に使いたいのか、それとも思いついたから気に入っただけなのかを判断する必要があります。
使用方法は次のとおりです。
A.デリゲートタイプを宣言する
typedef DELEGATE(float, ARGS(int, int)) Delegate1;
このマクロは、静的およびメンバー関数のポインター型を自動的に宣言するため、署名を 2 回入力する必要はありません。に展開しDelegate<float (*)(int, int), float (Null::*)(int, int)>
ます。コンパイラは、後で呼び出しを実行するためにデリゲート インスタンスがどのように初期化されたかに応じて、これらのいずれかを使用します。また、コンパイラはそれを使用して、コーダーの呼び出しによって提供された引数を静的に検証します。ARGS マクロは、戻り値の型から分離するための純粋な構文糖衣です: DELEGATE(float, int, int) は同じです。
B. 初期化:
Delegate1 d = Delegate1(test1); // static function
Delegate1 e = Delegate1((Delegate1::MemberType)&TestClass::test2, &obj); // member
これらの静的関数とメンバー関数は、同じ型として格納されるようになりました! obj は TestClass インスタンスへの有効なポインターである必要があり、TestClass::test2 は float を返し、上記のように (int, int) を引数として取得する必要があります。これは主な使用上の落とし穴です。コンパイラはここで行われた間違いを見つけることができません。
C. Invoke: INVOKE(d, ARGS(5, 6))
(この例では float を返します) 見た目とは裏腹に、この引数リストは実際には C++ 関数呼び出しと同じくらい型安全です! 上記で提供された前述の float (*)(int, int) シグネチャを使用して引数を検証します! 任意の数の引数をサポートできますが、署名と一致する必要があります。追加する引数が多すぎたり少なすぎたり、コンパイラから間違った引数の型を使用したりすると、わかりやすいコンパイラ エラーが発生します。繰り返しますが、ARGS はシンタックス シュガーでINVOKE(d, 5, 6)
あり、同じです。
しかし、承認しないコンパイラで INVOKE を使用すると、おそらくプログラムがクラッシュします:(
いくつか質問があります:
- 私の投稿した実装サンプルが正しく動作しない優れたコンパイラを誰か見つけることができますか?
- これが完全に機能するか、コンパイラ/プログラムが最初の使用時に反転することを願っています. しかし、しばらく動作しているように見えて、その後ランダムにクラッシュする可能性はありますか?
- あなたの意見では、これは使いやすい/きれいに見えますか? それとも、他の実装の方が簡単だと思いますか? どれ?どうにかして私の構文/使いやすさを改善する良い方法を考えてもらえますか?
- あなたはそれを使用しますか?それとも、弾丸を噛んで、より安全だがより複雑な代替ソリューションを使用する必要がありますか?