On 10/12/2010 1:24 PM, Eric Niebler wrote: > So it really seems to me that transform_expr is not necessary, but I may > be wrong.
I just confirmed this by trivially replacing uses of transform_expr with appropriate uses of nary_expr in your phoenix_test.cpp (attached). The only difference is the type of the last expression. Since pass_through transform leaves terminals alone, _1 ends up stored by reference in the transformed expression, which is perfectly OK and saves copies (admittedly trivial in this case). -- Eric Niebler BoostPro Computing http://www.boostpro.com
#include "stdafx.h" #include <boost/call_traits.hpp> #include <boost/ref.hpp> #include <boost/fusion/algorithm/iteration/for_each.hpp> #include <boost/mpl/eval_if.hpp> #include "visitor.hpp" #include "unpack.hpp" //#include "transform_expr.hpp" #include <iostream> #include <typeinfo> namespace boost { namespace phoenix { template <typename Tag> struct phoenix_grammar; template <template <typename> class Visitor> struct phoenix_visitor : proto::visitor<Visitor, phoenix_grammar> {}; template <typename Tag> struct generic_evaluator; //////////////////////////////////////////////////////////////////////////// // eval_grammar: // // We define our evaluation grammar/transform just here by using the meta // grammar with our generic_evaluator. typedef phoenix_visitor<generic_evaluator> eval_grammar; eval_grammar const eval = eval_grammar(); //////////////////////////////////////////////////////////////////////////// // Generic evaluator: // Depending on the given tag, the transform is called // // We dispatch on expression arity in our grammar, that means that // expression arity and generic::evaluator<Tag>::operator() arity needs to // match template <typename Tag> struct generic_evaluator : proto::_default<eval_grammar> {}; template <typename Tag> struct phoenix_grammar : proto::_ {}; template <typename Expr> struct actor; // the domain, same as before struct phoenix_domain : proto::domain< proto::pod_generator<actor>, proto::_, proto::default_domain> { template <typename T> struct as_child : as_expr<T> {}; }; struct default_domain_with_basic_expr : proto::domain<proto::use_basic_expr<proto::default_generator> > {}; //////////////////////////////////////////////////////////////////////////// // phoenix_expr_ex and phoenix_expr: // // base class for phoenix expressions, similar to the previous compose, but // but can now be used in proto grammars/transform // expression creation is now done with the static compose function template <typename Expr, typename Tag, template <typename> class Actor> struct phoenix_expr_ex; template <typename Expr, typename Tag> struct phoenix_expr : phoenix_expr_ex<Expr, Tag, actor> {}; template <typename A0, template <typename> class Expr, typename Tag, template <typename> class Actor> struct phoenix_expr_ex<Expr<A0>, Tag, Actor> : proto::transform<phoenix_expr_ex<Expr<A0>,Tag, Actor>, int> { typedef typename proto::result_of::make_expr<Tag, default_domain_with_basic_expr, A0>::type base_type; typedef Actor<base_type> type; typedef typename proto::unary_expr<Tag, A0>::proto_grammar proto_grammar; static type const compose(typename call_traits<A0>::param_type a0) { actor<base_type> const e = {{a0}}; return e; } template<typename E, typename S, typename D> struct impl : proto::transform_impl<E, S, D> { typedef E result_type; #ifdef BOOST_PROTO_STRICT_RESULT_OF result_type #else typename impl::expr_param #endif operator ()( typename impl::expr_param e , typename impl::state_param , typename impl::data_param ) const { return e; } }; typedef Tag proto_tag; typedef A0 proto_child0; }; template <typename A0, typename A1, template <typename, typename> class Expr, typename Tag, template <typename> class Actor> struct phoenix_expr_ex<Expr<A0, A1>, Tag, Actor> : proto::transform<phoenix_expr_ex<Expr<A0, A1>,Tag, Actor>, int> { typedef typename proto::result_of::make_expr<Tag, default_domain_with_basic_expr, A0, A1>::type base_type; typedef Actor<base_type> type; typedef typename proto::binary_expr<Tag, A0, A1>::proto_grammar proto_grammar; static type const compose(typename call_traits<A0>::param_type a0, typename call_traits<A1>::param_type a1) { actor<base_type> const e = {{a0, a1}}; return e; } template<typename E, typename S, typename D> struct impl : proto::transform_impl<E, S, D> { typedef E result_type; #ifdef BOOST_PROTO_STRICT_RESULT_OF result_type #else typename impl::expr_param #endif operator ()( typename impl::expr_param e , typename impl::state_param , typename impl::data_param ) const { return e; } }; typedef Tag proto_tag; typedef A0 proto_child0; typedef A1 proto_child1; }; template <typename A0, typename A1, typename A2, template <typename, typename, typename> class Expr, typename Tag, template <typename> class Actor> struct phoenix_expr_ex<Expr<A0, A1, A2>, Tag, Actor> : proto::transform<phoenix_expr_ex<Expr<A0, A1, A2>,Tag, Actor>, int> { typedef typename proto::result_of::make_expr<Tag, default_domain_with_basic_expr, A0, A1, A2>::type base_type; typedef Actor<base_type> type; typedef typename proto::nary_expr<Tag, A0, A1, A2>::proto_grammar proto_grammar; static type const compose( typename call_traits<A0>::param_type a0 , typename call_traits<A1>::param_type a1 , typename call_traits<A2>::param_type a2) { actor<base_type> const e = {{a0, a1, a2}}; return e; } template<typename E, typename S, typename D> struct impl : proto::transform_impl<E, S, D> { typedef E result_type; #ifdef BOOST_PROTO_STRICT_RESULT_OF result_type #else typename impl::expr_param #endif operator ()( typename impl::expr_param e , typename impl::state_param , typename impl::data_param ) const { return e; } }; typedef Tag proto_tag; typedef A0 proto_child0; typedef A1 proto_child1; typedef A2 proto_child2; }; // add more ... //////////////////////////////////////////////////////////////////////////// // actor is the same as with the previous design template <typename Expr> struct actor { BOOST_PROTO_BASIC_EXTENDS(Expr, actor<Expr>, phoenix_domain) BOOST_PROTO_EXTENDS_ASSIGN() BOOST_PROTO_EXTENDS_SUBSCRIPT() template <typename Sig> struct result; template <typename This, typename A0> struct result<This(A0)> : boost::result_of<eval_grammar(actor<Expr> const&, fusion::vector1<A0>&)> {}; template <typename A0> typename result<actor<Expr>(A0 const&)>::type operator()(A0 const& a0) const { fusion::vector1<A0 const&> env(a0); return eval(*this, env); } // add more ... }; //////////////////////////////////////////////////////////////////////////// // // Core ends here // //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // val is implemented as a plain proto terminal template <typename T> struct value : proto::terminal<T> {}; template <typename T> actor<typename value<T>::type> const val(T const& t) { actor<typename value<T>::type> const e = {t}; return e; } template <typename T> typename value<T>::type const val(T & t) { actor<typename value<T>::type> const e = {t}; return e; } //////////////////////////////////////////////////////////////////////////// // ref is implemented as a plain proto terminal with boost::ref as wrapper template <typename T> struct reference : proto::terminal<reference_wrapper<T> > {}; template <typename T> actor<typename reference<T const>::type> const cref(T const& t) { actor<typename reference<T const>::type> const e = {::boost::cref(t)}; return e; } // overload to handle boost::reference_wrapper directly template <typename T> actor<typename reference<T const>::type> const cref( reference_wrapper<T const> t) { actor<typename reference<T const>::type> const e = {t}; return e; } template <typename T> actor<typename reference<T>::type> const ref(T & t) { actor<typename reference<T>::type> const e = {::boost::ref(t)}; return e; } // overload to handle boost::reference_wrapper directly template <typename T> actor<typename reference<T>::type> const ref(reference_wrapper<T> t) { actor<typename reference<T>::type> const e = {t}; return e; } //////////////////////////////////////////////////////////////////////////// // Argument implementation // Note that we at first only define the phoenix expressions without exposure // of proto. namespace tag { struct argument; } template <typename N> struct argument : phoenix_expr<argument<N>, tag::argument> {}; namespace placeholders { argument<mpl::int_<0> >::type const _1 = {}; // more ... } struct argument_eval; // define the generic evaluator template <> struct generic_evaluator<tag::argument> : proto::unpack<argument_eval(proto::_value, proto::_state)> {}; struct argument_eval : proto::callable { template <typename Sig> struct result; template <typename This, typename N, typename Env> struct result<This(N, Env&)> : result<This(N const &, Env&)> {}; template <typename This, typename N, typename Env> struct result<This(N &, Env&)> : fusion::result_of::at_c<Env, N::value> { }; template <typename N, typename Env> typename fusion::result_of::at_c< Env , N::value >::type operator()(N &, Env& env) const { return fusion::at_c<N::value>(env); } template <typename N, typename Env> typename fusion::result_of::at_c< Env , N::value >::type operator()(N const &, Env& env) const { return fusion::at_c<N::value>(env); } }; //////////////////////////////////////////////////////////////////////////// // if, at first we only declare how our if_/else_ is going to be generated // note that no definition of any evaluation scheme is done here namespace tag { struct if_then; struct if_then_else; } template <typename Cond, typename Then, typename Else> struct if_then_else : phoenix_expr<if_then_else<Cond, Then, Else>, tag::if_then_else> {}; template <typename Cond, typename Then> struct else_gen { else_gen(Cond const& cond, Then const& then) : cond(cond), then(then) {} Cond const& cond; Then const& then; template <typename Else> typename if_then_else<Cond, Then, Else>::type const operator[](Else const& else_) const { return if_then_else<Cond, Then, Else>::compose(cond, then, else_); } }; template <typename Expr> struct if_actor : actor<Expr> { typedef actor<Expr> base_type; if_actor(base_type const& base) : base_type(base) , else_(proto::child_c<0>(*this), proto::child_c<1>(*this)) {} typedef typename proto::result_of::child_c<Expr, 0>::type cond_type; typedef typename proto::result_of::child_c<Expr, 1>::type then_type; else_gen<cond_type, then_type> else_; }; template <typename Cond, typename Then> struct if_then : phoenix_expr_ex<if_then<Cond, Then>, tag::if_then, if_actor> {}; template <typename Cond> struct if_gen { if_gen(Cond const& cond) : cond(cond) {} Cond const& cond; template <typename Then> typename if_then<Cond, Then>::type const operator[](Then const& then) const { return if_then<Cond, Then>::compose(cond, then); } }; template <typename Cond> if_gen<Cond> const if_(Cond const& cond) { return if_gen<Cond>(cond); } // Expression generation done. //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // finally, define how our generic_evaluator should evaluate our if_ struct if_then_eval; template <> struct generic_evaluator<tag::if_then> : proto::unpack<if_then_eval(proto::_, proto::_state)> {}; struct if_then_eval : proto::callable { typedef void result_type; // just like with the previous design, we get the to be evaluated // expressions as function parameters, neat! template <typename Cond, typename Then, typename Env> result_type operator()(Cond const& cond, Then const& then, Env& env) const { if(eval(cond, env)) eval(then, env); } }; //////////////////////////////////////////////////////////////////////////// // finally, define how our generic_evaluator should evaluate our if_ struct if_then_else_eval; template <> struct generic_evaluator<tag::if_then_else> : proto::unpack<if_then_else_eval(proto::_, proto::_state)> {}; struct if_then_else_eval : proto::callable { typedef void result_type; // just like with the previous design, we get the to be evaluated // expressions as function parameters, neat! template <typename Cond, typename Then, typename Else, typename Env> result_type operator()(Cond const& cond, Then const& then, Else const& else_, Env& env) const { if(eval(cond, env)) eval(then, env); else eval(else_, env); } }; }} #include <algorithm> #include <iostream> #include <string> #include <vector> namespace phoenix = boost::phoenix; namespace proto = boost::proto; namespace mpl = boost::mpl; // the new design enables proto grammars that can refer to phoenix expressions // in a somehow natural way, i.e. with they're names instead of proto::nary_expr<Tag, ...> struct test_grammar : phoenix::argument<proto::_> {}; struct if_test_grammar : proto::or_< phoenix::if_then_else<proto::_, proto::_, proto::_> , phoenix::if_then<proto::_, proto::_> > {}; template <typename Expr> void foo(Expr const& expr) { foo(expr, proto::matches<Expr, test_grammar>()); } template <typename Expr> void foo(Expr const& expr, mpl::true_) { std::cout << "argument!\n"; } template <typename Expr> void foo(Expr const& expr, mpl::false_) { std::cout << "no argument!\n"; } template <typename Expr> void if_foo(Expr const& expr) { if_foo(expr, proto::matches<Expr, if_test_grammar>()); } template <typename Expr> void if_foo(Expr const& expr, mpl::true_) { std::cout << "if statement!\n"; } template <typename Expr> void if_foo(Expr const& expr, mpl::false_) { std::cout << "no if statement!\n"; } template <typename Tag> struct constant_fold_visitor; typedef phoenix::phoenix_visitor<constant_fold_visitor> constant_folder; constant_folder const constant_fold = constant_folder(); template <typename Tag> struct constant_fold_visitor // : proto::transform_expr<constant_folder> : proto::nary_expr<proto::_, proto::vararg<constant_folder> > {}; //template <> //struct constant_fold_visitor<proto::tag::terminal> // : proto::_ //{}; struct constant_fold_extract_value : proto::when<proto::_, proto::_value(constant_folder(proto::_))> {}; template <typename FoldOp> struct folder : proto::if_< mpl::and_< proto::matches< constant_folder(proto::_child0) , phoenix::value<proto::_>::type >() , proto::matches< constant_folder(proto::_child1) , phoenix::value<proto::_>::type >() >() , proto::unpack<FoldOp(constant_fold_extract_value)> //, proto::transform_expr<constant_folder> , proto::nary_expr<proto::_, proto::vararg<constant_folder> > > {}; struct fold_plus; template <> struct constant_fold_visitor<proto::tag::plus> : folder<fold_plus> {}; struct fold_plus : proto::callable { template <typename Sig> struct result; template <typename This, typename T1, typename T2> struct result<This(T1, T2)> { typedef typename proto::detail::uncvref<T1>::type value_type; typedef phoenix::actor<typename phoenix::value<value_type>::type> const type; }; template <typename T1, typename T2> typename result<fold_plus(T1, T2)>::type operator()(T1 t1, T2 t2) { std::cout << "fold: " << t1 << " + " << t2 << "\n"; return phoenix::val(t1 + t2); } }; struct fold_multiply; template <> struct constant_fold_visitor<proto::tag::multiplies> : folder<fold_multiply> {}; struct fold_multiply : proto::callable { template <typename Sig> struct result; template <typename This, typename T1, typename T2> struct result<This(T1, T2)> { typedef typename proto::detail::uncvref<T1>::type value_type; typedef phoenix::actor<typename phoenix::value<value_type>::type> const type; }; template <typename T1, typename T2> typename result<fold_plus(T1, T2)>::type operator()(T1 t1, T2 t2) { std::cout << "fold: " << t1 << " * " << t2 << "\n"; return phoenix::val(t1 * t2); } }; int main() { using phoenix::val; using phoenix::ref; using phoenix::cref; using phoenix::placeholders::_1; std::cout << val(1)(0) << "\n"; std::cout << cref(2)(0) << "\n"; int i = 3; std::cout << ref(i)(0) << "\n"; std::cout << _1(10) << "\n"; // check if the expression is an argument foo( _1 ); // check if the expression is an if statement if_foo( _1 ); // check if the expression is an argument foo( val(1) ); // check if the expression is an if statement if_foo( val(1) ); if_(val(8) == 8)[ std::cout << val(std::string("success!\n")) ](0); // check if the expression is an if statement if_foo(if_(val(8) == 8)[ std::cout << val(std::string("success!\n")) ]); foo(if_(val(8) == 8)[ std::cout << val(std::string("success!\n")) ]); if_(val(9) == 8)[ std::cout << val(std::string("fail!\n")) ].else_[ std::cout << val(std::string("success!\n")) ](0); // check if the expression is an if statement if_foo(if_(val(9) == 8)[ std::cout << val(std::string("fail!\n")) ].else_[ std::cout << val(std::string("success!\n")) ]); // check if the expression is an argument foo(if_(val(9) == 8)[ std::cout << val(std::string("fail!\n")) ].else_[ std::cout << val(std::string("success!\n")) ]); std::vector<int> v; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); std::for_each(v.begin(), v.end(), if_(_1 % 2)[std::cout << _1 << std::string(" is odd\n")].else_[std::cout << _1 << std::string(" is even\n")]); std::cout << "\n"; std::cout << constant_fold(val(8) + val(9))(0) << "\n"; std::cout << "\n"; std::cout << constant_fold(val(8) + val(9) + val(10))(0) << "\n"; std::cout << "\n"; std::cout << constant_fold(_1 * (val(9) + val(10)))(10) << "\n"; std::cout << "\n"; std::cout << constant_fold(_1 * val(9) + val(10))(10) << "\n"; std::cout << "\n"; std::cout << constant_fold(val(10) * val(9) + val(10))(10) << "\n"; std::cout << constant_fold(val(8) + _1)(10) << "\n"; std::cout << "\n"; std::cout << typeid(constant_fold( val(8) + val(9))).name() << "\n\n"; std::cout << typeid(constant_fold( val(8) + val(9) + val(10))).name() << "\n\n"; std::cout << typeid(constant_fold( _1 * (val(7) + val(8)))).name() << "\n\n"; }
_______________________________________________ proto mailing list proto@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/proto