1///////////////////////////////////////////////////////////////////////////////
2// pack_expansion.hpp
3//
4// Copyright 2008 Eric Niebler. Distributed under the Boost
5// Software License, Version 1.0. (See accompanying file
6// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7
8#include <boost/proto/proto.hpp>
9#include <boost/test/unit_test.hpp>
10#include <boost/typeof/typeof.hpp>
11
12namespace mpl = boost::mpl;
13namespace proto = boost::proto;
14using proto::_;
15
16template<typename T> T declval();
17
18struct eval_ : proto::callable
19{
20 template<typename Sig>
21 struct result;
22
23#define UNARY_OP(TAG, OP) \
24 template<typename This, typename Arg> \
25 struct result<This(proto::tag::TAG, Arg)> \
26 { \
27 BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested, (OP declval<Arg>())) \
28 typedef typename nested::type type; \
29 }; \
30 \
31 template<typename Arg> \
32 typename result<eval_(proto::tag::TAG, Arg)>::type \
33 operator()(proto::tag::TAG, Arg arg) const \
34 { \
35 return OP arg; \
36 } \
37 /**/
38
39#define BINARY_OP(TAG, OP) \
40 template<typename This, typename Left, typename Right> \
41 struct result<This(proto::tag::TAG, Left, Right)> \
42 { \
43 BOOST_TYPEOF_NESTED_TYPEDEF_TPL(nested, (declval<Left>() OP declval<Right>())) \
44 typedef typename nested::type type; \
45 }; \
46 \
47 template<typename Left, typename Right> \
48 typename result<eval_(proto::tag::TAG, Left, Right)>::type \
49 operator()(proto::tag::TAG, Left left, Right right) const \
50 { \
51 return left OP right; \
52 } \
53 /**/
54
55 UNARY_OP(negate, -)
56 BINARY_OP(plus, +)
57 BINARY_OP(minus, -)
58 BINARY_OP(multiplies, *)
59 BINARY_OP(divides, /)
60 /*... others ...*/
61};
62
63struct eval1
64 : proto::or_<
65 proto::when<proto::terminal<_>, proto::_value>
66 , proto::otherwise<eval_(proto::tag_of<_>(), eval1(proto::pack(_))...)>
67 >
68{};
69
70struct eval2
71 : proto::or_<
72 proto::when<proto::terminal<_>, proto::_value>
73 , proto::otherwise<proto::call<eval_(proto::tag_of<_>(), eval2(proto::pack(_))...)> >
74 >
75{};
76
77void test_call_pack()
78{
79 proto::terminal<int>::type i = {.child0: 42};
80 int res = eval1()(i);
81 BOOST_CHECK_EQUAL(res, 42);
82 res = eval1()(i + 2);
83 BOOST_CHECK_EQUAL(res, 44);
84 res = eval1()(i * 2);
85 BOOST_CHECK_EQUAL(res, 84);
86 res = eval1()(i * 2 + 4);
87 BOOST_CHECK_EQUAL(res, 88);
88
89 res = eval2()(i + 2);
90 BOOST_CHECK_EQUAL(res, 44);
91 res = eval2()(i * 2);
92 BOOST_CHECK_EQUAL(res, 84);
93 res = eval2()(i * 2 + 4);
94 BOOST_CHECK_EQUAL(res, 88);
95}
96
97struct make_pair
98 : proto::when<
99 proto::binary_expr<_, proto::terminal<int>, proto::terminal<int> >
100 , std::pair<int, int>(proto::_value(proto::pack(_))...)
101 >
102{};
103
104void test_make_pack()
105{
106 proto::terminal<int>::type i = {.child0: 42};
107 std::pair<int, int> p = make_pair()(i + 43);
108 BOOST_CHECK_EQUAL(p.first, 42);
109 BOOST_CHECK_EQUAL(p.second, 43);
110}
111
112using namespace boost::unit_test;
113///////////////////////////////////////////////////////////////////////////////
114// init_unit_test_suite
115//
116test_suite* init_unit_test_suite( int argc, char* argv[] )
117{
118 test_suite *test = BOOST_TEST_SUITE("test immediate evaluation of proto parse trees");
119
120 test->add(BOOST_TEST_CASE(&test_call_pack));
121 test->add(BOOST_TEST_CASE(&test_make_pack));
122
123 return test;
124}
125

source code of boost/libs/proto/test/pack_expansion.cpp