calc3.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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. #include <iostream>
  12. #include <boost/mpl/int.hpp>
  13. #include <boost/mpl/assert.hpp>
  14. #include <boost/mpl/min_max.hpp>
  15. #include <boost/proto/core.hpp>
  16. #include <boost/proto/context.hpp>
  17. #include <boost/proto/transform.hpp>
  18. namespace mpl = boost::mpl;
  19. namespace proto = boost::proto;
  20. using proto::_;
  21. // Will be used to define the placeholders _1 and _2
  22. template<typename I> struct placeholder : I {};
  23. // This grammar basically says that a calculator expression is one of:
  24. // - A placeholder terminal
  25. // - Some other terminal
  26. // - Some non-terminal whose children are calculator expressions
  27. // In addition, it has transforms that say how to calculate the
  28. // expression arity for each of the three cases.
  29. struct CalculatorGrammar
  30. : proto::or_<
  31. // placeholders have a non-zero arity ...
  32. proto::when< proto::terminal< placeholder<_> >, proto::_value >
  33. // Any other terminals have arity 0 ...
  34. , proto::when< proto::terminal<_>, mpl::int_<0>() >
  35. // For any non-terminals, find the arity of the children and
  36. // take the maximum. This is recursive.
  37. , proto::when< proto::nary_expr<_, proto::vararg<_> >
  38. , proto::fold<_, mpl::int_<0>(), mpl::max<CalculatorGrammar, proto::_state>() > >
  39. >
  40. {};
  41. // Simple wrapper for calculating a calculator expression's arity.
  42. // It specifies mpl::int_<0> as the initial state. The data, which
  43. // is not used, is mpl::void_.
  44. template<typename Expr>
  45. struct calculator_arity
  46. : boost::result_of<CalculatorGrammar(Expr)>
  47. {};
  48. template<typename Expr>
  49. struct calculator_expression;
  50. // Tell proto how to generate expressions in the calculator_domain
  51. struct calculator_domain
  52. : proto::domain<proto::generator<calculator_expression> >
  53. {};
  54. // Define a calculator context, for evaluating arithmetic expressions
  55. // (This is as before, in calc1.cpp and calc2.cpp)
  56. struct calculator_context
  57. : proto::callable_context< calculator_context const >
  58. {
  59. // The values bound to the placeholders
  60. double d[2];
  61. // The result of evaluating arithmetic expressions
  62. typedef double result_type;
  63. explicit calculator_context(double d1 = 0., double d2 = 0.)
  64. {
  65. d[0] = d1;
  66. d[1] = d2;
  67. }
  68. // Handle the evaluation of the placeholder terminals
  69. template<typename I>
  70. double operator ()(proto::tag::terminal, placeholder<I>) const
  71. {
  72. return d[ I() - 1 ];
  73. }
  74. };
  75. // Wrap all calculator expressions in this type, which defines
  76. // operator () to evaluate the expression.
  77. template<typename Expr>
  78. struct calculator_expression
  79. : proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
  80. {
  81. typedef
  82. proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
  83. base_type;
  84. explicit calculator_expression(Expr const &expr = Expr())
  85. : base_type(expr)
  86. {}
  87. BOOST_PROTO_EXTENDS_USING_ASSIGN(calculator_expression<Expr>)
  88. // Override operator () to evaluate the expression
  89. double operator ()() const
  90. {
  91. // Assert that the expression has arity 0
  92. BOOST_MPL_ASSERT_RELATION(0, ==, calculator_arity<Expr>::type::value);
  93. calculator_context const ctx;
  94. return proto::eval(*this, ctx);
  95. }
  96. double operator ()(double d1) const
  97. {
  98. // Assert that the expression has arity 1
  99. BOOST_MPL_ASSERT_RELATION(1, ==, calculator_arity<Expr>::type::value);
  100. calculator_context const ctx(d1);
  101. return proto::eval(*this, ctx);
  102. }
  103. double operator ()(double d1, double d2) const
  104. {
  105. // Assert that the expression has arity 2
  106. BOOST_MPL_ASSERT_RELATION(2, ==, calculator_arity<Expr>::type::value);
  107. calculator_context const ctx(d1, d2);
  108. return proto::eval(*this, ctx);
  109. }
  110. };
  111. // Define some placeholders (notice they're wrapped in calculator_expression<>)
  112. calculator_expression<proto::terminal< placeholder< mpl::int_<1> > >::type> const _1;
  113. calculator_expression<proto::terminal< placeholder< mpl::int_<2> > >::type> const _2;
  114. // Now, our arithmetic expressions are immediately executable function objects:
  115. int main()
  116. {
  117. // Displays "5"
  118. std::cout << (_1 + 2.0)( 3.0 ) << std::endl;
  119. // Displays "6"
  120. std::cout << ( _1 * _2 )( 3.0, 2.0 ) << std::endl;
  121. // Displays "0.5"
  122. std::cout << ( (_1 - _2) / _2 )( 3.0, 2.0 ) << std::endl;
  123. // This won't compile because the arity of the
  124. // expression doesn't match the number of arguments
  125. // ( (_1 - _2) / _2 )( 3.0 );
  126. return 0;
  127. }
  128. //]