Boost.Proto をぺろぺろしてみる

ベクトル型の Expression Template を実装してみた。
すごく適当です。
こんな感じですか分かりません><

#include <iostream>
#include <boost/proto/proto.hpp>

namespace proto = boost::proto;

struct vec{
    int value[3];
};

vec
make_vec(int x, int y, int z){
    vec v = {x, y, z};
    return v;
}


// 式の評価
struct vec_context
    : proto::callable_context<const vec_context>{
    
    typedef int result_type;
    
    result_type
    operator ()(proto::tag::terminal, vec const& v) const{
        return v.value[index_];
    }
    
    result_type
    operator ()(proto::tag::terminal, int const& n) const{
        return n;
    }
    
    vec_context(int index) : index_(index){}
private:
    int index_;
};


// 演算を評価するための定義
struct grammar :
    proto::or_<
        proto::terminal<proto::_>,
        proto::plus<grammar, grammar>,
        proto::minus<grammar, grammar>,
        proto::multiplies<grammar, grammar>,
        proto::divides<grammar, grammar>
    >
{};

template<typename T>
struct vec_expr;

struct vec_domain :
    proto::domain<proto::generator<vec_expr>, grammar>{};

template<typename T>
struct vec_expr
    : proto::extends<T, vec_expr<T>, vec_domain>{
    explicit vec_expr(T const& t) : proto::extends<T, vec_expr<T>, vec_domain>(t){}
};


// 演算の定義
template<typename>
struct is_vec : boost::mpl::false_{};
template<>
struct is_vec<vec> : boost::mpl::true_{};
BOOST_PROTO_DEFINE_OPERATORS(is_vec, vec_domain);


// 式を評価する
template<typename Expr>
vec
eval(Expr const& expr){
    vec result = make_vec(0, 0, 0);
    for(int i = 0 ; i < 3 ; ++i){
        result.value[i] = proto::eval( proto::as_expr<vec_domain>(expr), vec_context(i) );
    }
    return result;
}

int
main(){
    vec v = make_vec(10, 20, 30);
    
    auto const& expr = v * 2 + 30;
    vec result = eval(expr);
//    vec result = eval(v + v + v);    // C++03 の場合
    
    std::cout << "x:" << result.value[0] << std::endl;
    std::cout << "y:" << result.value[1] << std::endl;
    std::cout << "z:" << result.value[2] << std::endl;
    
    return 0;
}

[出力]

x:50
y:70
z:90

ポイントなのは、『式を評価する際に、要素ごとに展開する』ところですかね。
これで無駄なコピーが行われません。
評価を行うタイミングも重要。
今回は、vec 型に何も定義したくなかったんで、eval 関数で評価を行っていますが、代入演算子で評価するのがセオリーなのかしら?
domain 回りは写経しただけなので、実は何をやっているのかよく分かっていません……。


んーベクトル演算ごときに Boost.Proto を使うのはちょっと微妙…と思わなくもない。
サックリと使う分にはいいけど、本格的に使うとなるとちょっと難しそうな感じがする。
あと Booooost するし。
使えそうなところを見極めて使っていきたいにゃー。


[参照]
http://www.kmonos.net/alang/boost/classes/proto.html
http://d.hatena.ne.jp/faith_and_brave/20090501/1241167261
http://www.slideshare.net/fjnl/boost4-boostproto