template で式を書く


template で式を定義し、実行時に展開を行うとかそんな感じです。
説明するよりも見たほうが早いと思うので、まずは使い方を。

// 処理を定義する。_1 は呼び出し時の引数
typedef plus<int_<2>, _1> plus_2_x;
int n = plus_2_x()(3);                // 2+ 3 を計算して返す
BOOST_ASSERT( n == 2 + 3);

// 2 + 3 を定義してみる
typedef plus<int_<2>, int_<3> > plus_3_2;
int n2 = plus_3_2()(void_());                // 引数がない場合は、void_ を渡す
BOOST_ASSERT( n2 == 3 + 2 );

// 両方共、引数でもおk
typedef plus<_1, _2> plus_x_y;
int n3 = plus_x_y()(
    fusion::make_vector(1, 2)  // 引数が複数の場合は、fusion でラップする
);
//apply(plus_x_y(), 1, 2);      // こう書くことも出来る
BOOST_ASSERT( n3 == 1 + 2 );

// 条件分岐
if_<is_even<_1>, _2, _3> even_func;
std::cout <<
    even_func(fusion::make_vector(2, std::string("even"), std::string("not even")))
<< std::endl;

std::cout <<
    even_func(fusion::make_vector(3, std::string("even"), std::string("not even")))
<< std::endl;

// 関数に渡してみたり
int array[] = {1, 2, 3, 4};
boost::for_each(array, print<plus<_1, _1> >());


[出力]

even
not even
2
4
6
8


template で式を定義して、実行時に処理を行っています。
定義の仕方は MPL で、実行時の処理は、Expression Template に近いのかな?
まぁ勢いで作ってみたものの自分でも使い勝手がよくわかりません……。
うーん、template 引数に渡しやすいとか?
効率のいい使い方を思いついた人はご一報下さい。


と、いうか boost::proto とか使えば似たような処理を作ることが出来るのかな?
とりあえず、本気で使うようであれば、可変長引数を fusion::vector でごまかしているのをなんとかしたい。
(あと適当になっている const 回りも)


実際のソースは続きからどうぞー。

#include <iostream>
#include <string>
#include <vector>

#include <boost/range/algorithm/for_each.hpp>
#include <boost/assert.hpp>

#include <boost/type_traits/is_same.hpp>
#include <boost/fusion/include/make_vector.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/include/at_c.hpp>
#include <boost/fusion/include/is_sequence.hpp>
#include <boost/fusion/mpl/at.hpp>

namespace mpl = boost::mpl;
namespace fusion = boost::fusion;


namespace detail{

template<int N>
struct args{
    template<typename args>
    struct result :
        mpl::if_<
            fusion::traits::is_sequence<args>,
            fusion::result_of::value_at_c<args, N>,
            mpl::identity<args>
            >::type
    {};

    template<typename args>
    typename result<args>::type
    operator ()(
        args const& v,
        typename boost::enable_if<
            fusion::traits::is_sequence<args>
        >::type* = 0) const{
        return fusion::at_c<N>(v);
    }
    // 引数が1個の場合で処理を切り替え
    template<typename args>
    typename result<args>::type
    operator ()(
        args const& v,
        typename boost::disable_if<
            fusion::traits::is_sequence<args>
        >::type* = 0) const{
        return v;
    }
};

} // namespace detail

//----------------------------------------------------------

typedef detail::args<0> _1;
typedef detail::args<1> _2;
typedef detail::args<2> _3;
typedef fusion::vector<> void_;

// 関数群
template<int N>
struct int_{
    template<typename T>
    struct result{
        typedef int type;
    };

    template<typename args>
    typename result<args>::type
    operator ()(args const&) const{
        return N;
    }
};
template<typename L, typename R>
struct plus{
    template<typename args>
    struct result{
        typedef typename L::template result<args>::type type;
    };

    template<typename args>
    typename result<args>::type
    operator ()(args const& v){
        return L()(v) + R()(v);
    }
};

template<typename B, typename THEN, typename ELSE>
struct if_{
    template<typename args>
    struct result{
        typedef typename THEN::template result<args>::type type;
    };

    template<typename args>
    typename result<args>::type
    operator ()(args const& v){
        if(B()(v)){
            return THEN()(v);
        }
        else{
            return ELSE()(v);
        };
    }
};
template<typename T>
struct is_even{
    template<typename args>
    struct result{
        typedef bool type;
    };

    template<typename args>
    typename result<args>::type
    operator ()(args const& v){
        return T()(v) % 2 == 0;
    }
};
template<typename T>
struct print{
    template<typename args>
    struct result{
        typedef void type;
    };
    template<typename args>
    void
    operator ()(args const& v){
        std::cout << T()(v) << std::endl;
    }
};

// 関数の引数を fusion にバインド
template<typename calc>
typename calc::template result<void_>::type
apply(const calc& c){
    return calc()(void_());
}
template<typename calc, typename P1>
typename calc::template result<fusion::vector<P1> >::type
apply(const calc& c, const P1& p1){
    return calc()(fusion::make_vector(p1));
}
template<typename calc, typename P1, typename P2>
typename calc::template result<fusion::vector<P1, P2> >::type
apply(const calc& c, P1 const & p1, P2 const& p2){
    return calc()(fusion::make_vector(p1, p2));
}

int
main(){
    
    // 処理を定義する。_1 は呼び出し時の引数
    typedef plus<int_<2>, _1> plus_2_x;
    int n = plus_2_x()(3);                // 2+ 3 を計算して返す
    BOOST_ASSERT( n == 2 + 3);

    // 2 + 3 を定義してみる
    typedef plus<int_<2>, int_<3> > plus_3_2;    
    int n2 = plus_3_2()(void_());                // 引数がない場合は、void_ を渡す
    BOOST_ASSERT( n2 == 3 + 2 );

    // 両方共、引数でもおk
    typedef plus<_1, _2> plus_x_y;
    int n3 = plus_x_y()(
        fusion::make_vector(1, 2)  // 引数が複数の場合は、fusion でラップする
    );
//    apply(plus_x_y(), 1, 2);    // こう書くことも出来る
    BOOST_ASSERT( n3 == 1 + 2 );
    
    // 条件分岐
    if_<is_even<_1>, _2, _3> even_func;
    std::cout <<
        even_func(fusion::make_vector(2, std::string("even"), std::string("not even")))
    << std::endl;
    
    std::cout <<
        even_func(fusion::make_vector(3, std::string("even"), std::string("not even")))
    << std::endl;

    // 関数に渡してみたり
    int array[] = {1, 2, 3, 4};
    boost::for_each(array, print<plus<_1, _1> >());

    return 0;
}