function9-perlを使ってみる
絶望した!preprocessorに絶望した!
可読性が悪すぎですね。。。
VCでデバッグするのも一苦労です。
偉い人が言ってましたが、「使っておいしいものは使え。使えるものは使うな。」
まさにこれですね。
ということで、perl使ってみましょう。とりあえずwindowsで手軽に使えるのはActivePerlですかね。
入門サイトはいくらでもあるので、google先生にお任せします。
私もほとんど触ったことがないですが、C言語に近いので入門サイトを見ながらすぐに使えるでしょう(たぶん)
perl
例えば以下のようなfunctionのベースとなるクラスをperlで生成してみましょう。
//戻り値R、引数0個のfunction template< typename R > class piyo< R ( void ) > { private: R ( *f )( void ); public: R operator()( void ) { return f( ); } }; //戻り値R、引数1個のfunction template< typename R, typename A1 > class piyo< R ( A1 ) > { private: R ( *f )( A1 ); public: R operator()( A1 a1 ) { return f( a1 ); } }; //戻り値R、引数2個のfunction template< typename R, typename A1, typename A2 > class piyo< R ( A1, A2 ) > { private: R ( *f )( A1, A2 ); public: R operator()( A1 a1, A2 a2 ) { return f( a1, a2 ); } };
以下、perlのソースです。適当です。突っ込みどころ満載かもしれません。
#引数の個数を入力 $n = <STDIN>; open( OUT, "> function.h" ); $void = "void"; for( $j = 0; $j < $n + 1; $j ++ ) { $comma = ""; $typename_A = ""; $A = $void; $A_a = $void; $a = ""; for( $i = 0; $i < $j; $i ++ ) { $k = $i + 1; $typename_A .= $comma."typename A$k"; #typename A1, ..., typename AN $A .= $comma."A$k"; #A1, ..., AN $A_a .= $comma."A$k a$k"; #A1 a1, ..., AN aN $a .= $comma."a$k"; #a1, ..., aN $comma = ", "; } print OUT "//戻り値R、引数$j個のfunction\n"; print OUT "template< typename R".$comma.$typename_A." >\n"; print OUT "class piyo< R ( ".$A." ) >\n"; print OUT "{\n"; print OUT "private:\n"; print OUT " R ( *f )( ".$A." );\n"; print OUT "\n"; print OUT "public:\n"; print OUT " R operator()( ".$A_a." )\n"; print OUT " {\n"; print OUT " return f( ".$a." );\n"; print OUT " }\n"; print OUT "};\n"; print OUT "\n"; $void = ""; } close( OUT );
ちゃんとソースが生成されたのでOKということにしておきましょう。
function
では、本題です。
前回function8-function+bind - while( c++ );のfunctionを、perlを使って一気に引数なし〜引数10個まで対応させましょう。
$n = <STDIN>; open( OUT, "> function_template.h" ); $void = "void"; for( $j = 0; $j < $n + 1; $j ++ ) { $comma = ""; $typename_A = ""; $A = $void; $A_a = $void; $a = ""; for( $i = 0; $i < $j; $i ++ ) { $k = $i + 1; $typename_A .= $comma."typename A$k"; $A .= $comma."A$k"; $A_a .= $comma."A$k a$k"; $a .= $comma."a$k"; $comma = ", "; } print OUT "//戻り値R、引数$j個のfunction\n"; print OUT "template< typename R".$comma.$typename_A." >\n"; print OUT "class function< R ( ".$A." ) >\n"; print OUT "{\n"; print OUT " typedef R result_t;\n"; print OUT "\n"; print OUT " class placeholder\n"; print OUT " {\n"; print OUT " public:\n"; print OUT " virtual ~placeholder(){}\n"; print OUT " virtual result_t invoke( ".$A." ) = 0;\n"; print OUT " };\n"; print OUT "\n"; print OUT " template< typename FuncT >\n"; print OUT " class holder\n"; print OUT " : public placeholder\n"; print OUT " {\n"; print OUT " public:\n"; print OUT " FuncT func;\n"; print OUT " \n"; print OUT " public:\n"; print OUT " holder( FuncT const& func )\n"; print OUT " : func( func )\n"; print OUT " {}\n"; print OUT "\n"; print OUT " public:\n"; print OUT " R invoke( ".$A_a." )\n"; print OUT " { return func( ".$a." ); }\n"; print OUT " };\n"; print OUT "\n"; print OUT "private:\n"; print OUT " shared_ptr< placeholder > content;\n"; print OUT "\n"; print OUT "public:\n"; print OUT " template< typename FuncT >\n"; print OUT " function& operator=( FuncT func )\n"; print OUT " {\n"; print OUT " content = shared_ptr< placeholder >( new holder< FuncT >( func ) );\n"; print OUT " return *this;\n"; print OUT " }\n"; print OUT "\n"; print OUT "public:\n"; print OUT " R operator()( ".$A_a." )\n"; print OUT " {\n"; print OUT " if( !content )throw bad_function_call();\n"; print OUT " return content->invoke( ".$a." );\n"; print OUT " }\n"; print OUT "};\n"; print OUT "\n"; $void = ""; } close( OUT );
実行結果
は、さすがにここでは無理ですねw
一応昨日のサンプルは動いてるので、正しく生成されているんでしょう。
mem_fun
ついでにmem_funもperlで作ります。
$n = <STDIN>; open( OUT, "> mem_fun_template.h" ); $void = "void"; for( $j = 0; $j < $n + 1; $j ++ ) { $comma = ""; $typename_A = ""; $A = ""; $A_a = ""; $a = ""; for( $i = 0; $i < $j; $i ++ ) { $k = $i + 1; $typename_A .= $comma."typename A$k"; $A .= $comma."A$k"; $A_a .= $comma."A$k a$k"; $a .= $comma."a$k"; $comma = ", "; } print OUT "template< typename R, typename T".$comma.$typename_A." >\n"; print OUT "class mem_fun$j\n"; print OUT "{\n"; print OUT " typedef R ( T::*F )( ".$A." );\n"; print OUT "private:\n"; print OUT " F f;\n"; print OUT "\n"; print OUT "public:\n"; print OUT " mem_fun$j( F f )\n"; print OUT " : f( f )\n"; print OUT " {}\n"; print OUT "\n"; print OUT "public:\n"; print OUT " R operator()( T* t".$comma.$A_a." )const\n"; print OUT " {\n"; print OUT " return ( t->*f )( ".$a." );\n"; print OUT " }\n"; print OUT " R operator()( T& t".$comma.$A_a." )const\n"; print OUT " {\n"; print OUT " return ( t.*f )( ".$a." );\n"; print OUT " }\n"; print OUT " template< typename U >\n"; print OUT " R operator()( U& u".$comma.$A_a." )const\n"; print OUT " {\n"; print OUT " return ( (*u).*f )( ".$a." );\n"; print OUT " }\n"; print OUT "};\n"; print OUT "\n"; $void = ""; } close( OUT );
bind、arg_list
同様にplファイルを作ります。面倒です。
download
- function_bind20081218.zip
- 引数無し〜10個まで対応
- VC++2008ExpressEdition用