...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
A Phoenix Expression is a model of the Proto
Expression Concept. These expressions are wrapped inside an Actor template. The actor
provides the function call operator which evaluates the expressions. The
actor
is the domain specific
wrapper around Phoenix expressions.
By design, Phoenix Expressions do not carry any information on how they will
be evaluated later on. They are the data structure on which the Actions
will work.
The library provides a convenience template to define expressions:
template <template <typename> Actor, typename Tag, typename A0, ..., typename A1> struct expr_ext : proto::transform<expr_ext<Actor, Tag, A0, ..., A1> > { typedef unspecified base_expr; typedef Actor<base_expr> type; typedef unspecified proto_grammar; static type make(A0 a0, ..., A1 a1); }; template <typename Tag, typename A0, ..., typename A1> struct expr : expr_ext<actor, Tag, A0, ..., A1> {};
Notation
A0...AN
Child node types
a0...aN
Child node objects
G0...GN
Boost.Proto grammar types
Expression Semantics
Expression |
Semantics |
---|---|
|
The type of Expression having tag |
|
A Boost.Proto grammar and Proto Pass Through Transform |
|
Returns a Phoenix Expression |
Note | |
---|---|
You might have noticed the template template argument |
Defining expressions is only part of the game to make it a valid Phoenix Expression. In order to use the expressions in the Phoenix domain, we need to "register" them to our grammar.
The meta_grammar
is a struct
for exactly that purpose. It is an openly extendable Boost.Proto
Grammar:
struct meta_grammar : proto::switch_<meta_grammar> { template <typename Tag, typename Dummy> struct case_ : proto::not_<proto::_> {}; };
As you can see, by default the meta_grammar
matches nothing. With every Module
you include this grammar gets extended by various expressions.
Define an expression:
template <typename Lhs, typename Rhs> struct plus : expr<proto::tag::plus, Lhs, Rhs> {};
And add it to the grammar:
template <> struct meta_grammar::case_<proto::tag::plus> : enable_rule< plus< meta_grammar , meta_grammar > > {};
Define a generator function to make the life of our potential users easier:
template <typename Lhs, typename Rhs> typename plus<Lhs, Rhs>::type plus(Lhs const & lhs, Rhs const & rhs) { return expression::plus<Lhs, Rhs>::make(lhs, rhs); }
Look if it really works:
plus(6, 5)();
returns 11!
proto::display_expr(plus(5, 6));
prints:
plus( terminal(6) , terminal(5) )
See define_expression.cpp for the full example.
Note | |
---|---|
The example shown here only works because |