The main objective of Boost.YAP is to be an easy-to-use and easy-to-understand library for using the expression template programming technique.
As such, it is very important that the way nodes in a Boost.YAP expression tree are represented matches the way nodes in C++ builtin expression are represented. This keeps the mental model for how to identify and manipulate parts of expression trees consistent across C++ builtin and Boost.YAP trees.
Though this creates minor difficulties (for instance, Boost.YAP terminals cannot contain arrays), the benefit of a consistent programming model is more important.
Boost.YAP expressions can be used as subexpressions to build larger expressions.
expr_kind::expr_ref
exists because we want to be able to do this without incurring unnecessay copies
or moves. Consider v2
and
v3
in this snippet from the
Lazy Vector example. Each is a terminal that owns its value, rather than referring
to it.
lazy_vector v2{{std::vector<double>(4, 2.0)}}; lazy_vector v3{{std::vector<double>(4, 3.0)}};
Now consider this expression:
double d1 = (v2 + v3)[2];
Without using reference semantics, how can we capture this expression, even
before evaluating it, without copying or moving the vectors? We cannot. We
must take references to the v2
and v3
subexpressions to avoid
copying or moving.
This comes at a cost. Dealing with expr_kind::expr_ref
expressions complicates user
code. The alternatives, silently incurring copies/moves or disallowing the
use of subexpressions to build larger expressions, are worse.