
Hi! I may have overlooked something, but while thinking about proto's design I was surprised by some asymmetry. I'd like to know why this was done the way it is. Consider two objects (type A and B are proto terminals) A a; B b; The expression a + b is considered equivalent to a function call operator+(a, b). The corresponding type representation approximately is expr<tag::binary_plus // I will vote for this ;-) ,args2<expr<tag::terminal, A> ,expr<tag::terminal, B> > > This is done according to the rationale that what binary_plus really means is domain specific. Therefore the expression is simply tagged by the name of the function call, while the second argument is the typelist containing the parameters in the same order as they appear in the expression. Important: any information about what the function call means is stored *outside* the expression. Up to here I appreciate the design and IMHO this is the most appropriate way to represent an expression (I said that before, I know). Now we introduce another function call - not an operator this time, but in C++ these are equivalent. struct fun_t {}; terminal<fun_t>::type const fun = {{}}; fun(a, b); This is represented by something similar to expr< tag::function ,args3< ref_<expr<tag::terminal, args0<fun_tag> > const> ,expr<tag::terminal, args0<> > ,expr<tag::terminal, args0<> > > > This is suprising. In contrast to operator+, the function fun is treated as if it was an *operand*, not an *operator*. The expression is not tagged by _the_ function call, but by a global this-is-a-function-tag and the function is stored in the argument typelist. What fun means is context dependent, I would expect the context to take care about what fun_t might mean, so if we want symmetry first I'd expect a type representation similar to expr< tag::function<fun_t> ,args2< ,expr<tag::terminal, args0<...ommitted...> > ,expr<tag::terminal, args0<...ommitted...> > >
So I wonder whether this asymmetry was introduced due to the fact that function objects could have a state which makes them an in-between between operator and operand ... Can we save state in tag::function<T> then? expr< tag::function<expr<tag::terminal, args0<fun_t> > > ,args2< ,expr<tag::terminal, args0<...ommitted...> > ,expr<tag::terminal, args0<...ommitted...> > >
I do not like that one either ... I ask because ripping the function off the argument list via fusion magic still looks odd to me and makes me feel uncomfortable: Any compile time algorithm has to fork for function calls if it is to apply an operation to the operands. Shed some light on this, please. Markus