1 //[ Calc3
2 //  Copyright 2008 Eric Niebler. Distributed under the Boost
3 //  Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 //
6 // This example enhances the arithmetic expression evaluator
7 // in calc2.cpp by using a proto transform to calculate the
8 // number of arguments an expression requires and using a
9 // compile-time assert to guarantee that the right number of
10 // arguments are actually specified.
11 
12 #include <iostream>
13 #include <boost/mpl/int.hpp>
14 #include <boost/mpl/assert.hpp>
15 #include <boost/mpl/min_max.hpp>
16 #include <boost/proto/core.hpp>
17 #include <boost/proto/context.hpp>
18 #include <boost/proto/transform.hpp>
19 namespace mpl = boost::mpl;
20 namespace proto = boost::proto;
21 using proto::_;
22 
23 // Will be used to define the placeholders _1 and _2
24 template<typename I> struct placeholder : I {};
25 
26 // This grammar basically says that a calculator expression is one of:
27 //   - A placeholder terminal
28 //   - Some other terminal
29 //   - Some non-terminal whose children are calculator expressions
30 // In addition, it has transforms that say how to calculate the
31 // expression arity for each of the three cases.
32 struct CalculatorGrammar
33   : proto::or_<
34 
35         // placeholders have a non-zero arity ...
36         proto::when< proto::terminal< placeholder<_> >, proto::_value >
37 
38         // Any other terminals have arity 0 ...
39       , proto::when< proto::terminal<_>, mpl::int_<0>() >
40 
41         // For any non-terminals, find the arity of the children and
42         // take the maximum. This is recursive.
43       , proto::when< proto::nary_expr<_, proto::vararg<_> >
44              , proto::fold<_, mpl::int_<0>(), mpl::max<CalculatorGrammar, proto::_state>() > >
45 
46     >
47 {};
48 
49 // Simple wrapper for calculating a calculator expression's arity.
50 // It specifies mpl::int_<0> as the initial state. The data, which
51 // is not used, is mpl::void_.
52 template<typename Expr>
53 struct calculator_arity
54   : boost::result_of<CalculatorGrammar(Expr)>
55 {};
56 
57 template<typename Expr>
58 struct calculator_expression;
59 
60 // Tell proto how to generate expressions in the calculator_domain
61 struct calculator_domain
62   : proto::domain<proto::generator<calculator_expression> >
63 {};
64 
65 // Define a calculator context, for evaluating arithmetic expressions
66 // (This is as before, in calc1.cpp and calc2.cpp)
67 struct calculator_context
68   : proto::callable_context< calculator_context const >
69 {
70     // The values bound to the placeholders
71     double d[2];
72 
73     // The result of evaluating arithmetic expressions
74     typedef double result_type;
75 
calculator_contextcalculator_context76     explicit calculator_context(double d1 = 0., double d2 = 0.)
77     {
78         d[0] = d1;
79         d[1] = d2;
80     }
81 
82     // Handle the evaluation of the placeholder terminals
83     template<typename I>
operator ()calculator_context84     double operator ()(proto::tag::terminal, placeholder<I>) const
85     {
86         return d[ I() - 1 ];
87     }
88 };
89 
90 // Wrap all calculator expressions in this type, which defines
91 // operator () to evaluate the expression.
92 template<typename Expr>
93 struct calculator_expression
94   : proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
95 {
96     typedef
97         proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
98     base_type;
99 
calculator_expressioncalculator_expression100     explicit calculator_expression(Expr const &expr = Expr())
101       : base_type(expr)
102     {}
103 
BOOST_PROTO_EXTENDS_USING_ASSIGNcalculator_expression104     BOOST_PROTO_EXTENDS_USING_ASSIGN(calculator_expression<Expr>)
105 
106     // Override operator () to evaluate the expression
107     double operator ()() const
108     {
109         // Assert that the expression has arity 0
110         BOOST_MPL_ASSERT_RELATION(0, ==, calculator_arity<Expr>::type::value);
111         calculator_context const ctx;
112         return proto::eval(*this, ctx);
113     }
114 
operator ()calculator_expression115     double operator ()(double d1) const
116     {
117         // Assert that the expression has arity 1
118         BOOST_MPL_ASSERT_RELATION(1, ==, calculator_arity<Expr>::type::value);
119         calculator_context const ctx(d1);
120         return proto::eval(*this, ctx);
121     }
122 
operator ()calculator_expression123     double operator ()(double d1, double d2) const
124     {
125         // Assert that the expression has arity 2
126         BOOST_MPL_ASSERT_RELATION(2, ==, calculator_arity<Expr>::type::value);
127         calculator_context const ctx(d1, d2);
128         return proto::eval(*this, ctx);
129     }
130 };
131 
132 // Define some placeholders (notice they're wrapped in calculator_expression<>)
133 calculator_expression<proto::terminal< placeholder< mpl::int_<1> > >::type> const _1;
134 calculator_expression<proto::terminal< placeholder< mpl::int_<2> > >::type> const _2;
135 
136 // Now, our arithmetic expressions are immediately executable function objects:
main()137 int main()
138 {
139     // Displays "5"
140     std::cout << (_1 + 2.0)( 3.0 ) << std::endl;
141 
142     // Displays "6"
143     std::cout << ( _1 * _2 )( 3.0, 2.0 ) << std::endl;
144 
145     // Displays "0.5"
146     std::cout << ( (_1 - _2) / _2 )( 3.0, 2.0 ) << std::endl;
147 
148     // This won't compile because the arity of the
149     // expression doesn't match the number of arguments
150     // ( (_1 - _2) / _2 )( 3.0 );
151 
152     return 0;
153 }
154 //]
155