Boost.Proto の式を型推論で評価する
うーん、こんな感じ?
#include <boost/proto/proto.hpp> #include <iostream> 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; } //-------------------------------------- // Boost.Proto struct vec_context : proto::callable_context<const vec_context>{ typedef int result_type; vec_context(int index) : index_(index){} 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; } private: int index_; }; // 演算を評価するための定義 struct grammar : proto::or_< proto::terminal<int>, proto::terminal<vec>, 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){} // 一部の要素のみの評価を行う int operator [](std::size_t i) const{ std::cout << "expression" << std::endl; return proto::eval(*this, vec_context(i) ); } // vec 型へ型推論する際に評価を行う operator vec() const{ vec result; for(int i = 0 ; i < 3 ; ++i){ result.value[i] = (*this)[i]; } return result; } }; // 演算の定義 template<typename> struct is_vec : boost::mpl::false_{}; template<> struct is_vec<vec> : boost::mpl::true_{}; BOOST_PROTO_DEFINE_OPERATORS(is_vec, vec_domain); int main(){ vec v = make_vec(10, 20, 30); vec v2 = make_vec(30, 20, 30); // vec 型に型推論する際に、評価が行われる vec result = (v + v2) * 2; std::cout << result.value[0] << std::endl; std::cout << result.value[1] << std::endl; std::cout << result.value[2] << std::endl; // 一部の要素のみ、評価を行う std::cout << (v + result)[0] << std::endl; return 0; }
[出力]
expression expression expression 80 80 120 expression 90
Boost.Proto で演算を行うと vec_expr 型を返すので、vec_expr に、operator vec() を定義すれば、型推論を行うことが出来ます。
これで、ユーザコードレベルで、proto::eval を行う必要がありません。
やったね!
[boost]
ver 1.46.1