/////////////////////////////////////////////////////////////////////////////// // pack_expansion.hpp // // Copyright 2008 Eric Niebler. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include #include #include namespace mpl = boost::mpl; namespace proto = boost::proto; using proto::_; template T declval(); struct eval_ : proto::callable { template struct result; #define UNARY_OP(TAG, OP) \ template \ struct result \ { \ BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested, (OP declval())) \ typedef typename nested::type type; \ }; \ \ template \ typename result::type \ operator()(proto::tag::TAG, Arg arg) const \ { \ return OP arg; \ } \ /**/ #define BINARY_OP(TAG, OP) \ template \ struct result \ { \ BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested, (declval() OP declval())) \ typedef typename nested::type type; \ }; \ \ template \ typename result::type \ operator()(proto::tag::TAG, Left left, Right right) const \ { \ return left OP right; \ } \ /**/ UNARY_OP(negate, -) BINARY_OP(plus, +) BINARY_OP(minus, -) BINARY_OP(multiplies, *) BINARY_OP(divides, /) /*... others ...*/ }; struct eval1 : proto::or_< proto::when, proto::_value> , proto::otherwise(), eval1(proto::pack(_))...)> > {}; struct eval2 : proto::or_< proto::when, proto::_value> , proto::otherwise(), eval2(proto::pack(_))...)> > > {}; void test_call_pack() { proto::terminal::type i = {42}; int res = eval1()(i); BOOST_CHECK_EQUAL(res, 42); res = eval1()(i + 2); BOOST_CHECK_EQUAL(res, 44); res = eval1()(i * 2); BOOST_CHECK_EQUAL(res, 84); res = eval1()(i * 2 + 4); BOOST_CHECK_EQUAL(res, 88); res = eval2()(i + 2); BOOST_CHECK_EQUAL(res, 44); res = eval2()(i * 2); BOOST_CHECK_EQUAL(res, 84); res = eval2()(i * 2 + 4); BOOST_CHECK_EQUAL(res, 88); } struct make_pair : proto::when< proto::binary_expr<_, proto::terminal, proto::terminal > , std::pair(proto::_value(proto::pack(_))...) > {}; void test_make_pack() { proto::terminal::type i = {42}; std::pair p = make_pair()(i + 43); BOOST_CHECK_EQUAL(p.first, 42); BOOST_CHECK_EQUAL(p.second, 43); } using namespace boost::unit_test; /////////////////////////////////////////////////////////////////////////////// // init_unit_test_suite // test_suite* init_unit_test_suite( int argc, char* argv[] ) { test_suite *test = BOOST_TEST_SUITE("test immediate evaluation of proto parse trees"); test->add(BOOST_TEST_CASE(&test_call_pack)); test->add(BOOST_TEST_CASE(&test_make_pack)); return test; }