hoge diary - October 30, 2006

[C++] delegate in C++

C# ではおなじみの delegate (デリゲート)ですが,C++/CLI でないただの C++ には当然そんなものはありません.今私が作っている C++ プログラムの機能を部分的にプラグイン化するにあたって,C# にあるあの便利な delegate の C++ 版がないかと思って探していると,いくつかの実装例を見つけました.

どちらの手法にも言えることは関数の引数(シグネチャ)をプログラム中にハードコーディングする必要がある,という点です.関数ポインタを使ってデリゲートを実装する以上,型をあらかじめ書く必要があるので仕方ないでしょう.

そんな中,Perl スクリプトを使用して,任意のシグネチャに対するデリゲートクラスを自動生成するアプローチがありました.

このスクリプトは,C# の delegate の定義によく似たファイル(以下)を入力として,

delegate void MyCallback( int a, int b, int c );

このファイルから,次のような C++ のヘッダファイルを生成する,というものです.

class MyCallback
{
public:
        virtual void Call( int a, int b, int c ) = 0;
};

template< class T >
class MyCallback_Delegate : public MyCallback
{
private:
        T* _that;
        void (T::*_func)( int a, int b, int c );

public:
        MyCallback_Delegate( T* that, void (T::*func)( int a, int b, int c ) )
        {
                _that = that;
                _func = func;
        }

        virtual void Call( int a, int b, int c ) {
                (_that->*_func)( a, b, c );
        }
};

template< class T >
inline MyCallback_Delegate<T>* new_MyCallback( T* that, void (T::*func)( int a, int b, int c ) )
{
        return new MyCallback_Delegate<T>( that, func );
}

呼び出す際には,次のようにします.

  1. まず最初に,デリゲート型のインスタンスを生成し,
    MyCallback* cb = new_MyCallback( this, &Receiver::DoStuff );
  2. 生成したインスタンスを使用して,呼び出しを行います.
    static void CallMeBack( MyCallback* cb )
    {
        cb->Call( 1, 2, 3 );
    }

関数ポインタの型が

void (T::*_func)( int a, int b, int c );

となっていますので,クラスの非 static なメンバ関数を呼び出せます.

この方法は,C++ における delegate の実装のうち,自動化できるところは徹底的に自動化したバージョンといえるでしょう.試しに使ってみようと思います.

なお,同じ文書中に,Perl スクリプトを用いない方法についても書いてありました.ただ,こちらの手法は渡す引数の数(型は問わない)に応じたテンプレートクラスを自分で書く必要があります.

コメント

名前(何でも可):

テキスト(http:// を含む内容は投稿できません):

トラックバック

トラックバック URI: https://www.pakunet.jp/hoge/trackback/2006103001

トラックバックはありません.


Valid XHTML 1.1! Valid CSS!
© 2004-2009 ぱくちゃん.
Last modified: Fri Nov 02 08:58:03 JST 2007