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