//#include "stdafx.h" #include #include #include #include #include #include #include namespace mpl = boost::mpl; namespace proto = boost::proto; namespace fusion = boost::fusion; using proto::_; struct term { friend std::ostream &operator<<(std::ostream &sout, term const &) { return sout << "term"; } }; template struct newterm { friend std::ostream &operator<<(std::ostream &sout, newterm const &) { return sout << "newterm<" << I::value << ">"; } }; proto::terminal::type const a = {{}}; proto::terminal::type const b = {{}}; proto::terminal::type const c = {{}}; struct make_pair : proto::callable { template struct result; template struct result { typedef std::pair type; }; template std::pair operator()(First const &first, Second const &second) const { return std::make_pair(first, second); } }; struct first : proto::callable { template struct result; template struct result { typedef typename Pair::first_type type; }; template typename Pair::first_type operator()(Pair const &pair) const { return pair.first; } }; struct second : proto::callable { template struct result; template struct result { typedef typename Pair::second_type type; }; template typename Pair::second_type operator()(Pair const &pair) const { return pair.second; } }; struct push_back : proto::callable { template struct result; template struct result : fusion::result_of::push_back< typename boost::add_const::type>::type , typename boost::remove_const::type>::type > {}; template typename fusion::result_of::push_back::type operator ()(Seq const &seq, T const &t) const { return fusion::push_back(seq, t); } }; struct unpack_expr : proto::callable { template struct result; template struct result : proto::result_of::unpack_expr {}; template typename proto::result_of::unpack_expr::type operator ()(Tag, Seq const &seq) const { return proto::unpack_expr(seq); } }; #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) #define _make_terminal(x) call #define Renumber(x,y) proto::call #define push_back(x,y) proto::call #define make_pair(x,y) proto::call #define unpack_expr(x,y) proto::call #define first(x) proto::call #define second(x) proto::call #endif struct Renumber; // don't evaluate T at runtime, but default-construct an object // of T's result type. template struct type_of : proto::make > {}; struct RenumberFun : proto::fold< _ , make_pair(fusion::vector<>(), proto::_state) , make_pair( push_back( first(proto::_state) , first(Renumber(_, second(proto::_state))) ) , type_of ) > {}; struct Renumber : proto::or_< proto::when< proto::terminal , make_pair( proto::_make_terminal(newterm()) , mpl::next() ) > , proto::when< proto::terminal<_> , make_pair(proto::_byval(_), proto::_state) > , proto::otherwise< make_pair( unpack_expr(proto::make >, first(RenumberFun)) , type_of ) > > {}; #if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1600)) #undef _make_terminal #undef Renumber #undef push_back #undef make_pair #undef unpack_expr #undef first #undef second #endif int main() { proto::display_expr((a + 1) + (b - c)); proto::display_expr(Renumber()((a + 1) + (b - c), mpl::int_<0>()).first); }