Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Adding an expression

This is not a toy example. This is actually part of the library. Remember the while lazy statement? Putting together everything we've learned so far, we eill present it here in its entirety (verbatim):

BOOST_PHOENIX_DEFINE_EXPRESSION(
    (boost)(phoenix)(while_)
  , (meta_grammar)           // Cond
    (meta_grammar)           // Do
)

namespace boost { namespace phoenix
{
    struct while_eval
    {
        typedef void result_type;

        template <typename Cond, typename Do, typename Context>
        result_type
        operator()(Cond const& cond, Do const& do_, Context & ctx) const
        {
            while(eval(cond, ctx))
            {
                eval(do_, ctx);
            }
        }
    };

    template <typename Dummy>
    struct default_actions::when<rule::while_, Dummy>
        : call<while_eval, Dummy>
    {};

    template <typename Cond>
    struct while_gen
    {
        while_gen(Cond const& cond) : cond(cond) {}

        template <typename Do>
        typename expression::while_<Cond, Do>::type const
        operator[](Do const& do_) const
        {
            return expression::while_<Cond, Do>::make(cond, do_);
        }

        Cond const& cond;
    };

    template <typename Cond>
    while_gen<Cond> const
    while_(Cond const& cond)
    {
        return while_gen<Cond>(cond);
    }
}}

while_eval is an example of how to evaluate an expression. It gets called in the rule::while action. while_gen and while_ are the expression template front ends. Let's break this apart to undestand what's happening. Let's start at the bottom. It's easier that way.

When you write:

while_(cond)

we generate an instance of while_gen<Cond>, where Cond is the type of cond. cond can be an arbitrarily complex actor expression. The while_gen template class has an operator[] accepting another expression. If we write:

while_(cond)
[
    do_
]

it will generate a proper composite with the type:

expression::while_<Cond, Do>::type

where Cond is the type of cond and Do is the type of do_. Notice how we are using Phoenix's Expression mechanism here

template <typename Do>
typename expression::while_<Cond, Do>::type const
operator[](Do const& do_) const
{
    return expression::while_<Cond, Do>::make(cond, do_);
}

Finally, the while_eval does its thing:

while(eval(cond, ctx))
{
    eval(do_, ctx);
}

cond and do_, at this point, are instances of Actor. cond and do_ are the Actors passed as parameters by call, ctx is the Context


PrevUpHomeNext