
Maurizio Vitale wrote:
Eric Niebler <eric@boost-consulting.com> writes:
Maurizio Vitale wrote:
Here's my code for adding a binary operator my_plus:
struct my_plus {};
template<typename Left, typename Right> proto::expr<my_plus, proto::args2<proto::ref_<Left>, proto::ref_<Right> > > const make_my_plus_expr(Left& left, Right& right) { typedef proto::expr<my_plus, proto::args2<proto::ref_<Left>, proto::ref_<Right> > > expr_type; expr_type that={left,right}; return proto::generate<typename Left::domain, expr_type>::make (that); }
Questions:
- is the above the right way, or is there some friendlier interface?
There's another way to achieve the same effect by just declaring a nullary my_plus and then let the proto machinery do its job by mean of operator()(). In this case the result would be: (function (terminal my_plus expr0 expr1))
The grammar can take care that only binary applications are allowed [my_plus could even declare its arity so that this can be done in a generic way]. What are pro/cons of the two solutions?
Right. I should have suggested that in the first place. I tend to think this approach (declaring an empty terminal and using its operator()()) is nicer because it reuses more of proto's machinery, but the two approaches are equivalent. There are cases where this approach doesn't work, however. For example, in xpressive, there is a repeat<>() function, for repeating sub-expressions. For instance: repeat<3,6>('a') will match between 3 and 6 'a' characters. In this case, "repeat" cannot be a proto terminal; it must be a function template. So I still need to make it easier to define custom "operators" like repeat() and your make_my_plus_expr(). As for "best practice," it's too early to say. We're making it up as we go. :-) -- Eric Niebler Boost Consulting www.boost-consulting.com