123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- //[ Calc3
- // 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)
- //
- // This example enhances the arithmetic expression evaluator
- // in calc2.cpp by using a proto transform to calculate the
- // number of arguments an expression requires and using a
- // compile-time assert to guarantee that the right number of
- // arguments are actually specified.
- #include <iostream>
- #include <boost/mpl/int.hpp>
- #include <boost/mpl/assert.hpp>
- #include <boost/mpl/min_max.hpp>
- #include <boost/proto/core.hpp>
- #include <boost/proto/context.hpp>
- #include <boost/proto/transform.hpp>
- namespace mpl = boost::mpl;
- namespace proto = boost::proto;
- using proto::_;
- // Will be used to define the placeholders _1 and _2
- template<typename I> struct placeholder : I {};
- // This grammar basically says that a calculator expression is one of:
- // - A placeholder terminal
- // - Some other terminal
- // - Some non-terminal whose children are calculator expressions
- // In addition, it has transforms that say how to calculate the
- // expression arity for each of the three cases.
- struct CalculatorGrammar
- : proto::or_<
- // placeholders have a non-zero arity ...
- proto::when< proto::terminal< placeholder<_> >, proto::_value >
- // Any other terminals have arity 0 ...
- , proto::when< proto::terminal<_>, mpl::int_<0>() >
- // For any non-terminals, find the arity of the children and
- // take the maximum. This is recursive.
- , proto::when< proto::nary_expr<_, proto::vararg<_> >
- , proto::fold<_, mpl::int_<0>(), mpl::max<CalculatorGrammar, proto::_state>() > >
- >
- {};
- // Simple wrapper for calculating a calculator expression's arity.
- // It specifies mpl::int_<0> as the initial state. The data, which
- // is not used, is mpl::void_.
- template<typename Expr>
- struct calculator_arity
- : boost::result_of<CalculatorGrammar(Expr)>
- {};
- template<typename Expr>
- struct calculator_expression;
- // Tell proto how to generate expressions in the calculator_domain
- struct calculator_domain
- : proto::domain<proto::generator<calculator_expression> >
- {};
- // Define a calculator context, for evaluating arithmetic expressions
- // (This is as before, in calc1.cpp and calc2.cpp)
- struct calculator_context
- : proto::callable_context< calculator_context const >
- {
- // The values bound to the placeholders
- double d[2];
- // The result of evaluating arithmetic expressions
- typedef double result_type;
- explicit calculator_context(double d1 = 0., double d2 = 0.)
- {
- d[0] = d1;
- d[1] = d2;
- }
- // Handle the evaluation of the placeholder terminals
- template<typename I>
- double operator ()(proto::tag::terminal, placeholder<I>) const
- {
- return d[ I() - 1 ];
- }
- };
- // Wrap all calculator expressions in this type, which defines
- // operator () to evaluate the expression.
- template<typename Expr>
- struct calculator_expression
- : proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
- {
- typedef
- proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
- base_type;
- explicit calculator_expression(Expr const &expr = Expr())
- : base_type(expr)
- {}
- BOOST_PROTO_EXTENDS_USING_ASSIGN(calculator_expression<Expr>)
- // Override operator () to evaluate the expression
- double operator ()() const
- {
- // Assert that the expression has arity 0
- BOOST_MPL_ASSERT_RELATION(0, ==, calculator_arity<Expr>::type::value);
- calculator_context const ctx;
- return proto::eval(*this, ctx);
- }
- double operator ()(double d1) const
- {
- // Assert that the expression has arity 1
- BOOST_MPL_ASSERT_RELATION(1, ==, calculator_arity<Expr>::type::value);
- calculator_context const ctx(d1);
- return proto::eval(*this, ctx);
- }
- double operator ()(double d1, double d2) const
- {
- // Assert that the expression has arity 2
- BOOST_MPL_ASSERT_RELATION(2, ==, calculator_arity<Expr>::type::value);
- calculator_context const ctx(d1, d2);
- return proto::eval(*this, ctx);
- }
- };
- // Define some placeholders (notice they're wrapped in calculator_expression<>)
- calculator_expression<proto::terminal< placeholder< mpl::int_<1> > >::type> const _1;
- calculator_expression<proto::terminal< placeholder< mpl::int_<2> > >::type> const _2;
- // Now, our arithmetic expressions are immediately executable function objects:
- int main()
- {
- // Displays "5"
- std::cout << (_1 + 2.0)( 3.0 ) << std::endl;
- // Displays "6"
- std::cout << ( _1 * _2 )( 3.0, 2.0 ) << std::endl;
- // Displays "0.5"
- std::cout << ( (_1 - _2) / _2 )( 3.0, 2.0 ) << std::endl;
- // This won't compile because the arity of the
- // expression doesn't match the number of arguments
- // ( (_1 - _2) / _2 )( 3.0 );
- return 0;
- }
- //]
|