function4-mem_fun
前回function3-mem_fun - while( c++ );の修正。
以下のように、
- Tの参照
- Tへのポインタ
- shared_ptr< T >
を受け取って、すべて同一の書き方で呼び出せるようなmem_funを作ります。
class Hoge { public: int func( int, float ) { return 1; } }; template< typename T, typename F > int piyo( T& t, F f ) { return f( t, 0, 0.0f ); } template< typename T, typename F > int piyo( T* t, F f ) { return f( t, 0, 0.0f ); } template< typename T, typename F > int piyo( shared_ptr< T >& t, F f ) { return f( t, 0, 0.0f ); } int main() { Hoge hoge; piyo( hoge, mem_fun( &Hoge::func ) ); piyo( &hoge, mem_fun( &Hoge::func ) ); shared_ptr< Hoge > p( new Hoge ); piyo( p, mem_fun( &Hoge::func ) ); return 0; }
mem_fun2
とりあえず戻り値R、引数2つのmem_funを作りますね。
//R:戻り値の型 //T:クラスT //A1:引数1の型 //A2:引数2の型 template< typename R, typename T, typename A1, typename A2 > class mem_fun2 { typedef R ( T::*func_t )( A1, A2 ); private: func_t f; public: mem_fun2( func_t f ) : f( f ) {} };
operator()
関数オブジェクトとして呼び出すので、それぞれTのポインタ、Tの参照、テンプレートUを引数にもつoperator()を定義します。
template< typename R, typename T, typename A1, typename A2 > class mem_fun2 { /*...*/ public: R operator()( T* t, A1 a1, A2 a2 ) { return ( t->*f )( a1, a2 ); } R operator()( T& t, A1 a1, A2 a2 ) { return ( t.*f )( a1, a2 ); } template< typename U > R operator()( U& u, A1 a1, A2 a2 ) { return ( (*u).*f )( a1, a2 ); } };
mem_funヘルパー関数
使いやすいようにヘルパー関数を用意します。
template< typename R, typename T, typename A1, typename A2 > mem_fun2< R, T, A1, A2 > mem_fun( R ( T::*f )( A1, A2 ) ) { return mem_fun2< R, T, A1, A2 >( f ); }
2個以上の引数
preprocessorで2個以上(0個〜N個)の引数にも対応させましょう。
以下の4箇所をpreprocessorで書き換えることが出来れば楽が出来そうです。
template< typename R, typename T, typename A1, typename A2, ... typename N >
typedef R ( T::*func_t )( A1, A2, ... AN );
R operator()( T* t, A1 a1, A2 a2, ..., AN aN )
return ( t->*f )( a1, a2, ..., aN );
pp_comma_if
Nが0の時、カンマが必要ないので、以前preprocessor - while( c++ );で作ったpp_ifで分岐しましょう。
#define pp_empty() #define pp_comma() , //cond != 0 -> , //cond == 0 -> なし #define pp_comma_if( cond ) pp_if( cond, pp_comma, pp_empty )()
pp_template_params
template< typename R, typename T, typename A1, typename A2, ... typename N >
これを以下のように書き換えます。
template< typename R, typename T pp_comma_if( N ) pp_template_params( N ) >
以前preprocessor - while( c++ );で作ったpp_repeatを使って、繰り返しましょう。
//pp_param( A, 0 ) -> A1 //pp_param( A, 1 ) -> A2 #define pp_param_n( p, n ) pp_cat( p, pp_inc( n ) ) //pp_enum_param( 0, A ) -> A1 //pp_enum_param( 1, A ) -> , A2 //pp_enum_param( 2, A ) -> , A3 #define pp_enum_param( n, p ) pp_comma_if( n ) pp_param_n( p, n ) //pp_enum_params( 0, A ) -> なし //pp_enum_params( 1, A ) -> A1 //pp_enum_params( 2, A ) -> A1, A2 //pp_enum_params( N, A ) -> A1, A2, ... AN #define pp_enum_params( n, p ) pp_repeat( n, pp_enum_param, p ) //pp_template_params( 0 ) -> なし //pp_template_params( 1 ) -> typename A1 //pp_template_params( 2 ) -> typename A1, typename A2 //pp_template_params( N ) -> typename A1, typename A2, ..., typename AN #define pp_template_params( n ) pp_enum_params( n, typename A )
template< typename R, typename T pp_comma_if( 0 ) pp_template_params( 0 ) > ↓展開すると template< typename R, typename T > template< typename R, typename T pp_comma_if( 2 ) pp_template_params( 2 ) > ↓展開すると template< typename R, typename T, typename A1, typename A2 >
pp_template_args
同様に、
typedef R ( T::*func_t )( A1, A2, ... AN );
これを以下のように書き換えます。
typedef R ( T::*func_t )( pp_template_args( N ) );
pp_template_paramsで作成済みですね。
/*...*/ //pp_template_args( 0 ) -> なし //pp_template_args( 1 ) -> A1 //pp_template_args( 2 ) -> A1, A2 //pp_template_args( N ) -> A1, A2, ..., AN #define pp_template_args( n ) pp_enum_params( n, A )
pp_function_args
次は、これを
return ( t->*f )( a1, a2, ..., aN );
以下のように書き換えます。
return ( t->*f )( pp_function_args( N ) );
pp_template_argsと同じです。
/*...*/ //pp_function_args( 0 ) -> なし //pp_function_args( 1 ) -> a1 //pp_function_args( 2 ) -> a1, a2 //pp_function_args( N ) -> a1, a2, ..., aN #define pp_function_args( n ) pp_enum_params( n, a )
pp_function_params
最後に、これを
R operator()( T* t, A1 a1, A2 a2, ..., AN aN )
以下のように書き換えます。
R operator()( T* t pp_comma_if( N ) pp_function_params( N ) )
ちょっと面倒です。
//pp_param2( 0 ) -> A1 a1 //pp_param2( 1 ) -> A2 a2 #define pp_param_n2( n ) pp_cat( A, pp_inc( n ) ) pp_cat( a, pp_inc( n ) ) //pp_enum_param2( 0 ) -> A1 a1 //pp_enum_param2( 1 ) -> , A2 a2 //pp_enum_param2( 2 ) -> , A3 a3 #define pp_enum_param2( n ) pp_comma_if( n ) pp_param_n2( n ) //pp_enum_params2( 0 ) -> なし //pp_enum_params2( 1 ) -> A1 a1 //pp_enum_params2( 2 ) -> A1 a1, A2 a2 //pp_enum_params2( N ) -> A1 a1, A2 a2, ..., AN aN #define pp_enum_params2( n ) pp_repeat( n, pp_enum_param, pp_empty )
完成
Nに引数の個数を指定して、必要な分だけコピペします。
#define N /*適当な値*/ template< typename R, typename T pp_comma_if( N ) pp_template_params( N ) > class pp_cat( mem_fun, N ) { typedef R ( T::*func_t )( pp_template_args( N ) ); private: func_t f; public: pp_cat( mem_fun, N )( func_t f ) : f( f ) {} public: R operator()( T* t pp_comma_if( N ) pp_function_args( N ) ) { return ( t->*f )( pp_function_args( N ) ); } R operator()( T& t pp_comma_if( N ) pp_function_args( N ) ) { return ( t.*f )( pp_function_args( N ) ); } template< typename U > R operator()( U& u pp_comma_if( N ) pp_function_args( N ) ) { return ( (*u).*f )( pp_function_args( N ) ); } }; #undef N
pp_inc(追記)
インクリメントした値を返す
#define pp_inc( n ) pp_inc_n( n ) #define pp_inc_n( n ) pp_cat( pp_inc_, n ) #define pp_inc_0 1 #define pp_inc_1 2 /*...*/ #define pp_inc_255 256
サンプルのダウンロード
- mem_fun.zip
- VC++2008ExpressEdition用