Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

6.2. Evaluating expressions containing - operators

[Note] Note

Note that you can find everything that has been included and defined so far here.

To fix the evaluation of expressions containing subtractions, we need to fix the function we use for summarising. We need to write a version that takes the operator being used into account.

First of all we will need the boost::mpl::minus metafunction for implementing subtraction:

> #include <boost/mpl/minus.hpp>

Let's write a helper metafunction that takes three arguments: the left operand, the operator and the right operand:

> template <class L, char Op, class R> struct eval_binary_op;
> template <class L, class R> struct eval_binary_op<L, '+', R> : boost::mpl::plus<L, R>::type {};
> template <class L, class R> struct eval_binary_op<L, '-', R> : boost::mpl::minus<L, R>::type {};

copy-paste friendly version

The first command declares the eval_binary_op metafunction. The first and third arguments are the left and right operands and the second argument is the operator.

[Note] Note

Note that it does not satisfy the expectations of a template metafunction since it takes the operator as a char and not as a class (or typename) argument. For simplicity, we will still call it a metafunction.

The second and third commands define the operation for the cases when the operator is + and -. When the eval_binary_op metafunction is called, the C++ compiler chooses one of the definitions based on the operator. If you have functional programming experience this approach (pattern matching) might be familiar to you. Let's try eval_binary_op out:

> eval_binary_op<boost::mpl::int_<11>, '+', boost::mpl::int_<2>>::type
mpl_::integral_c<int, 13>
> eval_binary_op<boost::mpl::int_<13>, '-', boost::mpl::int_<2>>::type
mpl_::integral_c<int, 11>

copy-paste friendly version

You might also try to use it with an operator it does not expect (yet). For example '*'. You will see the C++ compiler complaining about that the requested version of the eval_binary_op template has not been defined. This solution can be extended and support for the '*' operator can always be added later.

Let's write the metafunction we can use from the folding parser to evaluate the expressions using + and - operators. This takes two arguments:

Let's write the metafunction binary_op that takes these arguments and calls eval_binary_op:

> template <class S, class Item> \
...> struct binary_op : \
...>   eval_binary_op< \
...>     S, \
...>     boost::mpl::at_c<Item, 0>::type::value, \
...>     typename boost::mpl::at_c<Item, 1>::type \
...>   > \
...>   {};

copy-paste friendly version

This metafunction takes the operator (the first element) and the right operand (the second element) from Item. The operator is a class representing a character, such as mpl_::char_<'+'>. To get the character value out of it, one has to access its ::value. For example mpl_::char<'+'>::value is '+'. Since eval_binary_op takes this character value as its second argument, we had to pass boost::mpl::at_c<Item, 0>::type::value to it. Let's try it out:

> binary_op<boost::mpl::int_<11>, boost::mpl::vector<boost::mpl::char_<'+'>, boost::mpl::int_<2>>>::type
mpl_::integral_c<int, 13>

We passed it a number (11) and a vector of a character (+) and another number (2). It added the two numbers as expected. Let's use this function as the third argument of foldl_start_with_parser:

> using exp_parser13 = \
...> build_parser< \
...>   foldl_start_with_parser< \
...>     sequence<one_of<plus_token, minus_token>, int_token>, \
...>     int_token, \
...>     boost::mpl::quote2<binary_op> \
...>   > \
...> >;

copy-paste friendly version

It uses binary_op instead of sum_items. Let's try it out:

> exp_parser13::apply<BOOST_METAPARSE_STRING("1 + 2 - 3")>::type
mpl_::integral_c<int, 0>

It returns the correct result.


PrevUpHomeNext