function1

今日はboost::functionについて。
日記を書き始めるきっかけになったものです。
boost::functionの実装のために情報を探していた際、以下のエントリを見つけて感動しました。

ここを見れば、自力で実装できちゃいますね。偉大なる先人の方々に感謝です。
というか中の人は変態ですねw(褒め言葉です)

私も変態プログラマになれるよう気合入れていきますよ。(リンク先の方々はスーパー変態プログラマを超えたスーパー変態プログラマといったところですか?)


さて、本題。
lokiにはfunctorというクラスで同様のものが実装されていますが、正直見た目がよろしくないです。

loki::Functor< int, TYPELIST2( int, float ) > a = func; //int func( int, float );

Functor< ... >のテンプレート引数部分が嫌いです。美しくない。
boostでは以下のように書けます。

boost::function< int ( int, float ) > a = func;

同じ戻りと引数の型であれば、普通の関数、関数オブジェクト、メンバ関数すべて格納できます。しゅごい。。。

C++プログラマならこんなクラスを作ってみたいですよね?ね?


早速作ってみましょう。

タイプリストを使わずに、どのように戻り値と引数の型のセットを渡すのか

単純に書けばこうですね。
しかし、テンプレート引数をTで受け取ると、operator()の型がわかりません。

template< typname T >
class function
{
public:
    ? operator()( ?, ? );
};

答え。

template< typename T >
class function;

//戻り値R、引数T1、T2の特殊化バージョン
template< typename R, typename T1, typename T2 >
class function< R ( T1, T2 ) >
{
public:
    R operator()( T1 t1, T2 t2 );
};

卑怯ですね。こんな書き方できるなんて知りませんよ。
これをベースに関数を渡せるように改良しましょう。

template< typename T >
class function;

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

private:
    func_t* func_ptr;

public:
    template< typename FuncT >
    function( FuncT func )
        : func_ptr( func )
    {}

public:
    result_t operator()( T1 t1, T2 t2 )
    {
        return func_ptr( t1, t2 );
    }
};

int func( int, float )
{
    return 0;
}

int main()
{
    function< int ( int, float ) > a( func );
    int b = a( 0, 1.0f );
    std::cout << b << std::endl;

    return 0;
}

正しくbの値が表示されました。
第1段階突破です。