![]() |
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