function6-bind

function5-bind - while( c++ );の続き。

メンバ関数用bind

メンバ関数を呼び出すためには

が必要です。
呼び出し元の参照・ポインタを別で持たせてしまうと、グローバル関数・関数オブジェクトと、メンバ関数でbint_tを分けないといけないので、ちょっと気持ち悪いですね。
ということで、boostに倣って呼び出し元の参照・ポインタも引数の1つとして、引数を保持するためのlistNクラスを導入します。
ここではとりあえずarg_listNとします。

arg_listN

  • arg_listNはarg_listN-1を継承し、a1〜anまでの引数を保持する
//引数なし
template< typename R >
class arg_list0
{
protected:
    typedef R result_type;
};

//引数1
template<
    typename R
    , typename A1
    >
class arg_list1
    : public arg_list0< R >
{
protected:
    A1 a1;
public:
    arg_list1( A1 a1 )
        : arg_list0()
    {}
};

//引数2
template<
    typename R
    , typename A1
    , typename A2
    >
class arg_list2
    : public arg_list1< R, A1 >
{
protected:
    A2 a2;
public:
    arg_list2( A1 a1, A2 a2 )
        : arg_list1( a1 )
        , a2( a2 )
    {}
};

//引数3
template<
    typename R
    , typename A1
    , typename A2
    , typename A3
    >
class arg_list3
    : public arg_list2< R, A1, A2 >
{
protected:
    A3 a3;
public:
    arg_list3( A1 a1, A2 a2, A3 a3 )
        : arg_list2( a1, a2 )
        , a3( a3 )
    {}
};

とりあえず必要な分だけ用意しました。boostではplaceholderを使うためにもう少し違った実装になっています。

bind_t

上記のarg_listNを使ってbind_tも修正します。

template<
    typename R	//戻り値の型
    , typename F	//関数型
    , typename L	//引数リスト
	>
class bind_t
{
private:
    F f;
    L l;
public:
    bind_t( F const& f, L const& l )
        : f( f )
        , l( l )
    {}
};

arg_listNにoperator()を持たせると、bind_tで引数の個数を意識する必要はありません。

/*...*/
class bind_t
{
/*...*/
public:
    R operator()()
    {
        return l( f );
    }
};


//引数なし
template< typename R >
class arg_list0
{
/*...*/
public:
    template< typename F >
    result_type operator()( F& f )
    {
        return f();
    }
};

//引数1
/*...*/
class arg_list1
    : public arg_list0< R >
{
/*...*/
public:
    template< typename F >
    result_type operator()( F& f )
    {
        return f( a1 );
    }
};

//引数2
/*...*/
class arg_list2
    : public arg_list1< R, A1 >
{
/*...*/
public:
    template< typename F >
    result_type operator()( F& f )
    {
        return f( a1, a2 );
    }
};

//引数3
/*...*/
class arg_list3
    : public arg_list2< R, A1, A2 >
{
/*...*/
public:
    template< typename F >
    result_type operator()( F& f )
    {
        return f( a1, a2, a3 );
    }
};

bind

最後に各bindを修正します。

  • メンバ関数用は呼び出し元も普通の引数としてarg_list3を使用する
//グローバル関数用
template<
    typename R		//戻り値の型
    , typename A1	//引数1の型
    , typename A2
    >
bind_t< R, R ( * )( A1, A2 ), arg_list2< R, A1, A2 > >
bind( R ( *f )( A1, A2 ), A1 a1, A2 a2 )
{
    typedef R result_type;
    typedef result_type ( *func_type )( A1, A2 );
    typedef arg_list2< R, A1, A2 > arg_list;
    typedef bind_t< result_type, func_type, arg_list > bind_type;

    return bind_type( f, arg_list( a1, a2 ) );
}

//関数オブジェクト用
template<
    typename R		//戻り値の型
    , typename F	//関数オブジェクト
    , typename A1	//引数1の型
    , typename A2
    >
bind_t< R, F, arg_list2< R, A1, A2 > >
bind( F f, A1 a1, A2 a2 )
{
    typedef R result_type;
    typedef F func_type;
    typedef arg_list2< R, A1, A2 > arg_list;
    typedef bind_t< result_type, func_type, arg_list > bind_type;

    return bind_type( f, arg_list( a1, a2 ) );
}

//メンバ関数用
template<
    typename R		//戻り値の型
    , typename T	//クラスT
    , typename B1	//メンバ関数の引数1の型
    , typename B2
    , typename A1	//引数1の型
    , typename A2
    , typename A3
    >
bind_t< R, mem_fun2< R, T, B1, B2 >, arg_list3< R, A1, A2, A3 > >
bind( R ( T::*f )( B1, B2 ), A1 a1, A2 a2, A3 a3 )
{
    typedef R result_type;
    typedef mem_fun2< result_type, T, B1, B2 > func_type;
    typedef arg_list3< R, A1, A2, A3 > arg_list;
    typedef bind_t< result_type, func_type, arg_list > bind_type;

    return bind_type( f, arg_list( a1, a2, a3 ) );
}

実行結果


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

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

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

int main()
{
    bind( hoge, 0, 1.0f )();
    bind< int >( piyo(), 0, 1.0f )();
    bind( &fuga::func, fuga(), 0, 1.0f )();
    bind( &fuga::func, new fuga, 0, 1.0f )();

    boost::bind( hoge, 0, 1.0f )();
    boost::bind< int >( piyo(), 0, 1.0f )();
    boost::bind( &fuga::func, fuga(), 0, 1.0f )();
    boost::bind( &fuga::func, new fuga, 0, 1.0f )();

    return 0;
}
  • deleteは自分でやってくださいw

次回はpreprocessorを使って、2個以上の引数にも対応させます。

サンプル

  • bind.zip 直
  • VC++2008ExpressEdition用です。
  • 引数2つまで。
  • deleteしてませんよ。