[proto] docs unclear (to me) for: "Expression Nodes as Fusion Sequences"

Hi! In the section "Expression Nodes as Fusion Sequences" you show the follwing code struct fun_t {}; 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 , functional::arg<>() ) , display() ); It did not became clear to me why a terminal<fun_t>::type can be initialized with 4 integer arguments. I thought terminal<fun_t>::type is equivalent to expr< tag::terminal, args0< fun_t >, 0 > and should take no args at all. Could you clarify this? Markus

Markus Werle wrote:
Hi!
In the section "Expression Nodes as Fusion Sequences" you show the follwing code
struct fun_t {}; 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 , functional::arg<>() ) , display() );
It did not became clear to me why a terminal<fun_t>::type can be initialized with 4 integer arguments.
"fun" is an object. It is already initialized.
I thought terminal<fun_t>::type is equivalent to expr< tag::terminal, args0< fun_t >, 0 > and should take no args at all. Could you clarify this?
"fun(1,2,3,4)" is an invocation of an overloaded function call operator. Proto is an expression template library ... all operators are overloaded to build expression trees. This operator builds a tree node representing a function invocation. HTH, -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric Niebler <eric <at> boost-consulting.com> writes:
Markus Werle wrote:
Hi!
In the section "Expression Nodes as Fusion Sequences" you show the follwing code
struct fun_t {}; 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 , functional::arg<>() ) , display() );
It did not became clear to me why a terminal<fun_t>::type can be initialized with 4 integer arguments.
"fun" is an object. It is already initialized.
I should be careful about how I ask, sorry for the stupid error. I meant operator call not initialization, but I had in mind that fun(1, 2, 3, 4) initializes some sort of expr<>, see questions below.
I thought terminal<fun_t>::type is equivalent to expr< tag::terminal, args0< fun_t >, 0 > and should take no args at all. Could you clarify this?
"fun(1,2,3,4)" is an invocation of an overloaded function call operator.
OK, for me it was not clear from the docs why fun is a function object (or similar thing) that takes 4 arguments - or more. Up to this point in the docs no operator() was mentioned (or I overlooked it)
Proto is an expression template library ... all operators are overloaded to build expression trees.
Now since my reputation is lost anyway, let's go on asking further stupid questions: 1. fun is of type expr< tag::terminal, args0< fun_t >, 0 > - right? 2. a terminal expression like "fun" has a set of overloaded operators for an arbitrary number of operators (until some PROTO_MAX_SIZE_WHATEVER) that returns a fusion compatible sequence? 3.For me a terminal is a "do-nothing", a holder. I get confused now. Here the terminal has some magic behind the scenes which I would not expect at this place. A terminal with arity 0 takes 4 arguments. I do not get that into my thick skull.
This operator builds a tree node representing a function invocation.
What is the resulting type of the function call fun(1, 2, 3, 4)? I would have expected to see "whatever(1, 2, 3, 4)" be represented as expr<tag::noop, args4<int, int, int, int> >. Now I read this like the function call itself is stored as a NOOP-leaf with 4 arguments ... getting lost. Markus

Markus Werle wrote:
Eric Niebler <eric <at> boost-consulting.com> writes:
"fun(1,2,3,4)" is an invocation of an overloaded function call operator.
OK, for me it was not clear from the docs why fun is a function object (or similar thing) that takes 4 arguments - or more. Up to this point in the docs no operator() was mentioned (or I overlooked it)
"fun" is a node in an expression tree. Proto overloads *all* operators for Proto expressions. So you can say "fun + fun" and build a new node representing an addition. Or you can say "fun(fun)" to build a new node representing a function call. You could even say "(fun + fun)(fun, fun fun)". But that would be too much fun. :-)
Proto is an expression template library ... all operators are overloaded to build expression trees.
Now since my reputation is lost anyway, let's go on asking further stupid questions:
1. fun is of type expr< tag::terminal, args0< fun_t >, 0 > - right?
Yes.
2. a terminal expression like "fun" has a set of overloaded operators for an arbitrary number of operators (until some PROTO_MAX_SIZE_WHATEVER) that returns a fusion compatible sequence?
Yes, up to BOOST_PROTO_MAX_ARITY operands.
3.For me a terminal is a "do-nothing", a holder. I get confused now. Here the terminal has some magic behind the scenes which I would not expect at this place. A terminal with arity 0 takes 4 arguments. I do not get that into my thick skull.
It's just an overloaded function call operator. All Proto expression types, terminals and non-terminals, have them.
This operator builds a tree node representing a function invocation.
What is the resulting type of the function call fun(1, 2, 3, 4)? I would have expected to see "whatever(1, 2, 3, 4)" be represented as expr<tag::noop, args4<int, int, int, int> >. Now I read this like the function call itself is stored as a NOOP-leaf with 4 arguments ... getting lost.
The type of "fun(1,2,3,4)" would look something like: expr< tag::function ,args5< ref_<expr<tag::terminal, args0<fun_tag> > const> ,expr<tag::terminal, args0<int const &> > ,expr<tag::terminal, args0<int const &> > ,expr<tag::terminal, args0<int const &> > ,expr<tag::terminal, args0<int const &> >
HTH, -- Eric Niebler Boost Consulting www.boost-consulting.com

So you can say "fun + fun" and build a new node representing an addition. Or you can say "fun(fun)" to build a new node representing a function call. You could even say "(fun + fun)(fun, fun fun)". But that would be too much fun.
Is the following statement correct: expr< tag::terminal, args0< placeholder_t >, 0 >::operator()(...args...) returns an expression representation that during evaluation via proto::eval() first evaluates its arguments and then delegates the result to to placeholder_t::operator()( ... args... ). In contrast to this all other operators (+, -, *, / etc.) return an expression representation that during evaluation via proto::eval(expr, context) first evaluates its arguments and then delegates the result to context::operator()(proto::tag::xxx, ...args...) If the above is correct: can I write my_context::operator()(proto::tag::fucntion, ...args...) to catch it first and hinder delegation to placeholder_t::operator()(...args...)? (Sorry if this is answered later in the docs, I am not through yet) Markus

Markus Werle wrote:
So you can say "fun + fun" and build a new node representing an addition. Or you can say "fun(fun)" to build a new node representing a function call. You could even say "(fun + fun)(fun, fun fun)". But that would be too much fun.
Is the following statement correct:
expr< tag::terminal, args0< placeholder_t >, 0 >::operator()(...args...) returns an expression representation that during evaluation via proto::eval() first evaluates its arguments and then delegates the result to to placeholder_t::operator()( ... args... ).
No. proto::eval() has no behavior independent of a context and treats no expression types specially. If you are talking about how the default_context handles tag::function, then the answer is, almost. For a default_context C and an expression E with E::proto_tag of tag::function, then proto::eval(E, C) is equivalent to: proto::eval(proto::arg_c<0>(E),C)( proto::eval(proto::arg_c<1>(E),C) ,proto::eval(proto::arg_c<2>(E),C) ,... ) So the left-most arg is evaluated and the result is treated as a callable object. The rest of the arguments are evaluated and their results are treated as arguments to the callable object. In your case, the result of evaluating a placeholder_t terminal with the default_context is simply the placeholder_t object itself. In that case, yes, the default_context would dispatch to any placeholder_t::operator().
In contrast to this all other operators (+, -, *, / etc.) return an expression representation that during evaluation via proto::eval(expr, context) first evaluates its arguments and then delegates the result to context::operator()(proto::tag::xxx, ...args...)
operator()'s handling is consistent with the other operators.
If the above is correct: can I write my_context::operator()(proto::tag::fucntion, ...args...) to catch it first and hinder delegation to placeholder_t::operator()(...args...)?
Yes, you can specify in your context how tag::function expressions should be handled. -- Eric Niebler Boost Consulting www.boost-consulting.com
participants (2)
-
Eric Niebler
-
Markus Werle