function2

前回function1 - while( c++ );の続き。
テンプレート引数に戻り値、引数の型を指定して、通常の関数を格納することが出来ました。

int hoge( int, float ){ /*...*/ }

int main()
{
    function< int ( int, float ) > a( hoge );
    int b = a( 1, 2.0f );    //hoge( 1, 2.0 );

    return 0;
}

次に、operator()を持つ関数オブジェクトも同様に格納したいですね。

struct piyo
{
    int operator()( int, float ){ /*...*/ }
};

int main()
{
    function< int ( int, float ) > a( piyo() );
    int b = a( 1, 2.0f );    //piyo::operator()( 1, 2.0 );

    return 0;
}

function内部で関数ポインタと関数オブジェクトを保持する必要があります。
いろんな実装方法があると思いますが、まずはshared_ptrのように

class base;

template< typename T >
class derived : public base;

関数ポインタ、関数オブジェクトを格納しておくためのクラスを用意しましょう。一般的には「placeholder」と呼ぶんですかね??boost::anyでも使われているアレです。

template< typename T >
class function;

//戻り値R、引数T1、T2の特殊化バージョン
template< typename R, typename T1, typename T2 >
class function< R ( T1, T2 ) >
{
    typedef R result_t;

    class placeholder
    {
    public:
        virtual ~placeholder(){}
        virtual result_t invoke( T1, T2 ) = 0;
    };

    template< typename FuncT >
    class holder
        : public placeholder
    {
    public:
        FuncT func;
	
    public:
        holder( FuncT const& func )
            : func( func )
        {}

    public:
        result_t invoke( T1 t1, T2 t2 )
        { return func( t1, t2 ); }
    };
    /*...*/
};

holder< FuncT >で、関数ポインタ、関数オブジェクトを両方受け取ることが出来ます。

次に、functionでsahred_ptr< placeholder >を持たせましょう。

//戻り値R、引数T1、T2の特殊化バージョン
template< typename R, typename T1, typename T2 >
class function< R ( T1, T2 ) >
{
    /*...*/
private:
    shared_ptr< placeholder > content;

public:
    template< typename FuncT >
    void set( FuncT func )
    {
        content = shared_ptr< placeholder >( new holder< FuncT >( func ) );
    }

public:
    result_t operator()( T1 t1, T2 t2 )
    {
        return content->invoke( t1, t2 );
    }
};

実際に使ってみましょう。

int hoge( int, float ){ /*...*/ }

struct piyo
{
    int operator()( int, float ){ /*...*/ }
};

int main()
{
    function< int ( int, float ) > a;

    a.set( hoge );
    int b = a( 1, 2.0f );

    piyo p;
    a.set( p );
    int c = a( 1, 2.0f );

    return 0;
}

とりあえず、動くものが出来ました。しかし、このfunctionもboost::functionとは完全に別物ですね。さて、どうしましょうか。
boost::functionは仮想関数を使わない形で実装しています。ただ、今の段階ではその形にメリットが感じられません。。。勉強不足です。

次回はメンバ関数も扱えるように拡張していきましょう。

download