function8-function+bind

前回function7-placeholder - while( c++ );の続き。

以前function2 - while( c++ );のサンプルを多少修正したfunctionです。

  • operator=でcontentの設定
//function.contentが0の場合に投げる例外
class bad_function_call{};

//基本形
template< typename T >
class function;

//戻り値R、引数2つの特殊化バージョン
template< typename R, typename A1, typename A2 >
class function< R ( A1, A2 ) >
{
    typedef R result_type;

    class placeholder
    {
    public:
        virtual ~placeholder(){}
        virtual result_type invoke( A1, A2 ) = 0;
    };

    template< typename FuncT >
    class holder
        : public placeholder
    {
    public:
        FuncT func;
	
    public:
        holder( FuncT const& func )
            : func( func )
            {}

    public:
        result_type invoke( A1 a1, A2 a2 )
        { return func( a1, a2 ); }
    };

private:
    shared_ptr< placeholder > content;

public:
    template< typename FuncT >
    function& operator=( FuncT func )
    {
        content = shared_ptr< placeholder >( new holder< FuncT >( func ) );
        return *this;
    }

public:
    result_type operator()( A1 a1, A2 a2 )
    {
        if( !content )throw bad_function_call();
        return content->invoke( a1, a2 );
    }
};

bindが完成したので、メンバ関数の呼び出しも可能なはずです。
前回と同様に以下の3つの関数で試して見ましょう。

int hoge( int x, float y )
{
    std::cout << "hoge:" << x << "," << y << std::endl;
    return 1;
}

struct piyo
{
    int operator()( int x, float y )
    {
        std::cout << "piyo::operator():" << x << "," << y << std::endl;
        return 2;
    }
};

class fuga
{
public:
    int func( int x, float y )
    {
        std::cout << "fuga::func:" << x << "," << y << std::endl;
        return 3;
    }
};

boostと同じ使い方が出来れば問題ないですよね?

  • placeholderが重複しないように、自作したものはnamespace xtlにしています。
  • fugaのdeleteを行っていません。
int main()
{
    {
        xtl::function< int ( int, float ) > f;
        //グローバル関数
        f = hoge;
        f( 0, 1.0f );
        //関数オブジェクト
        f = piyo();
        f( 0, 1.0f );
        //メンバ関数
        f = xtl::bind( &fuga::func, new fuga, xtl::_1, xtl::_2 );
        f( 0, 1.0f );
    }

    {
        boost::function< int ( int, float ) > f;
        //グローバル関数
        f = hoge;
        f( 0, 1.0f );
        //関数オブジェクト
        f = piyo();
        f( 0, 1.0f );
        //メンバ関数
        f = boost::bind( &fuga::func, new fuga, _1, _2 );
        f( 0, 1.0f );
    }

    return 0;
}

実行結果

おおおおおおおお!ちゃんと実行できてますねw


boost::functionに自作bindを渡しても、正しく動作しているようです。

    {
        boost::function< int ( int, float ) > f;
        //自作bindでメンバ関数
        f = xtl::bind( &fuga::func, new fuga, xtl::_1, xtl::_2 );
        f( 0, 1.0f );
    }

download

次回予定

  • preprocessorで3個以上の引数
  • perlでソースを自動生成
  • functionでウィンドウプロシージャをC#delegate風に