mirror of
https://github.com/boostorg/yap.git
synced 2026-02-23 16:22:09 +00:00
199 lines
5.2 KiB
Plaintext
199 lines
5.2 KiB
Plaintext
[section Examples]
|
|
|
|
Most of these examples are patterned after the examples from Boost.Proto. In
|
|
part, this was done to underscore where _yap_ can do what Proto can, and where
|
|
it cannot.
|
|
|
|
Where possible, a Proto-derived example uses syntax in `main()` identical to
|
|
that in the original Proto example.
|
|
|
|
|
|
[section Hello World]
|
|
|
|
Welp. Remember how I mentioned earlier that _yap_ does things in a completely
|
|
lazy way? There's no easy way to get the same line of code that you saw in
|
|
`main()` in the Proto version of this example, because _yap_ doesn't know that
|
|
it should evaluate your expression eagerly in this case. It can be done, but
|
|
it's a bit of code. This is one case in which Proto's eager evaluation can
|
|
prove easier to use than _yap_'s lazy evaluation.
|
|
|
|
[hello_world]
|
|
|
|
[endsect]
|
|
|
|
|
|
[section Hello World Redux]
|
|
|
|
That's better! Sort of.... We created a custom expression template with an
|
|
eager stream operator. This gives us eager evaluation, but gives away all the
|
|
lazy AST building-then-evaluating that we're using _ets_ for in the first
|
|
place. In this simple example, we don't really need it.
|
|
|
|
[hello_world_redux]
|
|
|
|
[endsect]
|
|
|
|
|
|
[section Minimal]
|
|
|
|
`minimal_expr` below models _ExprTmpl_; since it has no operators, an
|
|
expression is built manually.
|
|
|
|
First, the template itself:
|
|
|
|
[minimal_template]
|
|
|
|
This can be used to make a `minimal_expr` plus expression:
|
|
|
|
[minimal_template_manual_construction]
|
|
|
|
You can evaluate, transform, or otherwise operate on `minimal_expr`
|
|
expressions using the functions in _yap_ that accept an _Expr_:
|
|
|
|
[minimal_template_evaluation]
|
|
|
|
[note Don't use _yap_ this way. Use the operator macros instead. This is an
|
|
example contrived only to show you the minimum requirements on a
|
|
_yap_-compatible template.]
|
|
|
|
[endsect]
|
|
|
|
|
|
[section Calc1]
|
|
|
|
This is the first of several calculator-building examples derived from Proto.
|
|
This first one just builds lazy expressions with placeholders, and evaluates
|
|
them. Here we can first see how much C++14-and-later language features help
|
|
the end user -- the Proto version is much, much longer.
|
|
|
|
[calc1]
|
|
|
|
[endsect]
|
|
|
|
|
|
[section Calc2]
|
|
|
|
The Proto Calc2 example turns the expressions from Calc1 into callable
|
|
objects. Using _yap_ you can do this in two ways.
|
|
|
|
You can just use lambdas to wrap the expressions:
|
|
|
|
[calc2a]
|
|
|
|
Or you can use _make_expr_fn_ to make a callable object from your expression:
|
|
|
|
[calc2b]
|
|
|
|
[endsect]
|
|
|
|
|
|
[section Calc3]
|
|
|
|
Here, we introduce a _XForm_ used to calculate expression arity, and
|
|
`static_assert()` that the number of parameters passed by the caller matches
|
|
the arity.
|
|
|
|
[note The `get_arity` _XForm_ doesn't produce an _Expr_, and it does not have
|
|
to. _XForms_ may produce _Exprs_ or arbitrary values. They may also have
|
|
arbitrary side effects, and may be stateful.]
|
|
|
|
[calc3]
|
|
|
|
[endsect]
|
|
|
|
|
|
[section Lazy Vector]
|
|
|
|
Finally, it starts to get interesting! This example shows how you can add
|
|
plus and other operations to sequences of data without creating temporaries
|
|
and allocating memory.
|
|
|
|
[note In this example, we see a terminal type that owns the storage of its
|
|
value, a `std::vector<double>`. See the Vector example later on to see a
|
|
terminal type that does not.]
|
|
|
|
[lazy_vector]
|
|
|
|
[endsect]
|
|
|
|
|
|
[section TArray]
|
|
|
|
Proto refers to this as the "mini-library for linear algebra" example. It
|
|
shows how quite complicated expressions involving sequences can be evaliated
|
|
elementwise, requiring no temporaries.
|
|
|
|
[note The original Proto example used a terminal that contained an array of
|
|
three `int`s; _yap_ cannot represent this, and so this example uses a
|
|
`std::array<T, 3>` instead. _yap_ decays `int[3]` to `int *`, since that is
|
|
what is done in a C++ expression. See _how_treated_ for details.]
|
|
|
|
[tarray]
|
|
|
|
[endsect]
|
|
|
|
|
|
[section Vec3]
|
|
|
|
An example using 3-space vectors, a bit like the tarray example.
|
|
|
|
[vec3]
|
|
|
|
[endsect]
|
|
|
|
|
|
[section Vector]
|
|
|
|
So far we've only seen examples with custom terminals that own the values in
|
|
the expressions we operate on. What happens when you've got types that you
|
|
want to operate on, non-intrusively? Here's how you might do it with
|
|
`std::vector<>`s:
|
|
|
|
[vector]
|
|
|
|
[note Though this example only provides overloads for the operations we want
|
|
to define over `std::vector<>`s, the result of each of those operations is an
|
|
_expr_, which uses *all* the operator overloads. If we wanted to restrict the
|
|
operations on the results too, we could have defined a custom expression
|
|
template with the desired operations, and used that instead of _expr_ in the
|
|
operator macros.]
|
|
|
|
[endsect]
|
|
|
|
|
|
[section Mixed]
|
|
|
|
This is a lot like the previous Vector example, except that it operates on
|
|
`std::vector<>`s and `std::list<>`s in the same expression. It also shows how
|
|
to override one of the operator-evaluation customization points.
|
|
|
|
[mixed]
|
|
|
|
[endsect]
|
|
|
|
|
|
[section Map Assign]
|
|
|
|
An implementation of `map_list_of()` from Boost.Assign using _yap_.
|
|
|
|
[map_assign]
|
|
|
|
[note `map_list_of_expr` defines a generic call operator that matches any
|
|
call, including one with the wrong number of arguments. This could be fixed
|
|
by adding a `static_assert()` to the `map_list_of_expr` template, or by
|
|
hand-writing the call operator with SFNIAE or concept constraints.]
|
|
|
|
[endsect]
|
|
|
|
|
|
[section Future Group]
|
|
|
|
An implementation of Howard Hinnant's design for /future groups/.
|
|
|
|
[future_group]
|
|
|
|
[endsect]
|
|
|
|
|
|
[endsect]
|