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個以上の引数にも対応させます。