
On Wednesday 11 July 2007 01:47, Eric Niebler wrote:
So, how can I look at code like the following and know that it's wrong?
Grammar::call(proto::right(expr),state,visitor)
Because it violates the Transform Protocol. Grammar::call() invokes the transform associated with Grammar. expr matches Grammar, but right(expr) probably doesn't. To pass right(expr) to Grammar::call() would be to pass it an expression it doesn't know how to handle. A nasty compile error is sure to result.
Ok, that makes sense, I think.
Perhaps what you mean to say is:
return(new typename apply<Expr, State, Visitor>::type( proto::arg(proto::left(Grammar::call(expr,state,visitor))), proto::right(Grammar::call(expr,state,visitor))));
But it's hard to know without seeing more of your code.
Ok, I think I see what you're getting at. Yes, I think this is what I want. I was getting confused about transform::call() vs. Grammar::call(), thinking that what you suggest here would be infinite recursion. But I see that's not the case. In essence the code here is "walking up" the inheritance tree from subclass (transform) to superclass (Grammar), yes? And Grammar::call will do the same with whatever it's inherited from. And by default built-in proto expressions do a pass-through. Because proto uses CRTP, "walking up" the inheritance tree is in effect "walking down" the proto expression tree, and since Grammar::call is always invoked first, transforms are built bottom-up. I hope I've got that right.
transform::arg is implemented in terms of proto::arg, and its implementation is simple and perhaps enlightening. Here is the implementation of transform::arg<Grammar,N>::call(expr,state,visitor)
return proto::arg<N>(Grammar::call(expr, state, visitor));
It follows the pattern of invoking Grammar's transform, then manipulating the result. That is how the chaining of transforms works.
Many of the transforms are just that simple. Once you really grok the Transform Protocol, it won't seem so mysterious. I hope. :-)
Yes, this explanation was extremely helpful. I'm not at the level of grok yet but I'm getting there. I had to stare at what you wrote here for a few minutes, but it makes good sense.
Does this make sense? Is it possible?
Yes, it's possible, but not documented anywhere. My fault. You can say Expr::proto_arity::value, which is a compile-time integral constant. Nicer would be a proto::arity<> metafunction. I'll add it.
Cool. -Dave