![]() |
Home | Libraries | People | FAQ | More |
Boost.Fusion is a library of iterators, algorithms, containers and adaptors
for manipulating heterogeneous sequences. In essence, a Proto expression
is just a heterogeneous sequence of its child expressions, and so Proto
expressions are valid Fusion random-access sequences. That means you can
apply Fusion algorithms to them, transform them, apply Fusion filters and
views to them, and access their elements using fusion::at()
. The things Fusion can do to heterogeneous
sequences are beyond the scope of this users' guide, but below is a simple
example. It takes a lazy function invocation like fun(1,2,3,4)
and uses Fusion to print the function arguments in order.
struct display { template<typename T> void operator()(T const &t) const { std::cout << t << std::endl; } }; struct fun_t {}; proto::terminal<fun_t>::type const fun = {{}}; // ... fusion::for_each( fusion::transform( // pop_front() removes the "fun" child fusion::pop_front(fun(1,2,3,4)) // Extract the ints from the terminal nodes , proto::functional::value() ) , display() );
Recall from the Introduction that types in the proto::functional
namespace define function objects that correspond to Proto's free functions.
So proto::functional::value()
creates a function object that is equivalent to the proto::value()
function. The above invocation of fusion::for_each()
displays the following:
1 2 3 4
Terminals are also valid Fusion sequences. They contain exactly one element: their value.
Imagine a slight variation of the above example where, instead of iterating over the arguments of a lazy function invocation, we would like to iterate over the terminals in an addition expression:
proto::terminal<int>::type const _1 = {1}; // ERROR: this doesn't work! Why? fusion::for_each( fusion::transform( _1 + 2 + 3 + 4 , proto::functional::value() ) , display() );
The reason this doesn't work is because the expression _1
+ 2 + 3 +
4
does not describe a flat sequence
of terminals --- it describes a binary tree. We can treat it as a flat
sequence of terminals, however, using Proto's proto::flatten()
function. proto::flatten()
returns a view which makes
a tree appear as a flat Fusion sequence. If the top-most node has a tag
type T
, then the elements
of the flattened sequence are the child nodes that do not
have tag type T
. This process
is evaluated recursively. So the above can correctly be written as:
proto::terminal<int>::type const _1 = {1}; // OK, iterate over a flattened view fusion::for_each( fusion::transform( proto::flatten(_1 + 2 + 3 + 4) , proto::functional::value() ) , display() );
The above invocation of fusion::for_each()
displays the following:
1 2 3 4