...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
Expression is the central
concept in Boost.YAP. It must contain at least an expr_kind
and a boost::hana::tuple<>
of values.
Here is a summary of the requirements on Expression.
In the tables below, E
is a
type that models Expression;
e
is an object of type E
; Tuple
is an instantiation of boost::hana::tuple<>
;
and t
is an object of type
Tuple
.
Table 48.6. Expression Requirements
Expression |
Type |
Description |
Notes |
---|---|---|---|
|
The kind of expression |
Must be a compile-time constant. |
|
|
|
The child expressions of |
The types of the elements must be appropriate to the kind of the expression. |
|
Construction/initialization of |
|
As stated above, the elements
data member must match the kind of the expression:
Table 48.7. Expression Requirements
|
|
Possible Tuple Element Types |
Notes |
---|---|---|---|
|
1 |
Any non- |
|
|
1 |
Any non-Expression. |
A terminal with a |
Any unary operator |
1 |
Any Expression. |
|
Any binary operator |
2 |
Any Expression. |
|
|
3 |
Any Expression. |
|
|
Any number >= 1. |
Any Expression. |
ExpressionTemplate
is any template with two parameters that, when instantiated with an expr_kind
and a boost::hana::tuple<>
, results in an Expression.
transform()
takes a Transform
as its second parameter. A Transform
is a Callable
that takes expressions and returns values of unconstrained type. There are
two sorts of overloads Transform
may use: ExpressionTransform
and TagTransform.
A Transform may have any number of overloads, including none.
ExpressionTransform takes an Expression as its only parameter. Here are some examples.
This one takes any Expression:
struct xform { template <typename Expr> auto operator() (Expr const & expr) { // ... } };
This one takes any type of Expression that satisfies the constraints imposed by its template parameters:
template <typename Expr1, typename Expr2, typename Expr3> decltype(auto) xform ( boost::yap::expression< boost::yap::expr_kind::plus, boost::hana::tuple< boost::yap::expression< boost::yap::expr_kind::multiplies, boost::hana::tuple< Expr1, Expr2 > >, Expr3 > > const & expr ) { // ... }
This one takes only a specific type:
decltype(auto) xform ( decltype(term<number>{{0.0}} * number{} + number{}) const & expr ) { // ... }
TagTransform takes a tag-type as its first parameter, and the individual elements of an expression as the remaining parameters.
Tags are named such that the tag for an expression with expr_kind
expr_kind::foo
is
named foo_tag
. Here are some
examples.
This one takes any terminal that contains a user::number
(or reference to such a terminal):
struct xform { decltype(auto) operator() (boost::yap::terminal_tag, user::number const & n) { // ... } };
This one takes any plus expression that contains a pair of user::number
terminals (or references to terminals):
decltype(auto) xform (boost::yap::plus_tag, user::number lhs, user::number rhs) { // ... }
This one takes any negation expression:
struct xform { template <typename Expr> decltype(auto) operator() (boost::yap::negate_tag, Expr const & expr) { // ... } };
This one takes any call expression with two terminals (or references to terminals)
containing values convertible to double
:
struct xform { decltype(auto) operator() (boost::yap::call_tag, tag_type, double a, double b) { // ... } }