Boost logo

Boost :

From: Eric Niebler (eric_at_[hidden])
Date: 2008-03-10 12:29:38

Steven Watanabe wrote:
> Markus Werle wrote:
>> Hi!
>> I want to discuss the internal data structure expr<>:
>> I like the way expr<> is built regarding to the first and second
>> template argument: It is well thought and done to have the
>> expression tag as first argument and some fusion-compatible
>> typelist as its second argument containing the operands.

The typelist used there is not Fusion-compatible, but expr<> as a whole
is. For a while, I was using mpl::vector<> as the second template
parameter to expr<>, but I changed to a very simple custom type because
it improved compile times.

>> OTOH the third template argument contains redundant information:
>> The docs say: "Proto expression nodes are valid Fusion random-access
>> sequences of their children nodes."
>> So the information about the number of arguments is accessible via
>> some size<T>::type metafunction e.g. depending on
>> result_of::distance<result_of::begin<S>::type
>> result_of::end<S>::type>::type?

That's true.

>> In my unfinished attempts to write a paper about ET library design
>> (now obsolote, thanks to Eric) I have a statement that any expression
>> representation taking more than 2 template arguments is wrong.
>> Eric, since you always have a good reason for your design:
>> Could you please elaborate on this?
> I believe that it is needed to allow partial specialization.
> expr<Tag, Args, 0>, expr<Tag, Args, 1>, ...
> And users don't need to care about it, since it has a default.

Steven has it right. The expr<> struct has no primary implementation ...
just specializations. And it is designed to be POD where possible so
that it can be statically initialized. Considering that the
implementation of a binary expr must differ from that of a unary expr,
the only way I could do that would be to add a defaulted template
parameter on which I could create specializations.

There was another reason, too. Users might want to be able to overload
on the arity of an expression.

// handle unary expressions
template<typename Tag, typename Args>
void foo(expr<Tag, Args, 1> const &e);

// handle binary expressions
template<typename Tag, typename Args>
void foo(expr<Tag, Args, 2> const &e);

This sort of thing was common in the bad old days before Proto had
grammars and transforms. It's not as important now, but still a
nice-to-have, IMO.

>> Also I ask myself whether there was a good reason not to follow
>> mpl and use types to represent numbers.
>> I'd prefer at least some parallism to mpl here: size_t<c>?

Yes, I've considered this, and I'm willing to change it. The original
reason for going with raw numbers was to make the overloading trick
above easier. (Users don't have to worry, is it a size_t<> or an int_<>
or a ...?) Since the overloading trick is not commonly needed I don't
have strong feelings about it. The only bad thing about that change is
that it would make the debug symbols for complicated expressions even
longer, and give users longer compiler error messages to wade through.


Eric Niebler
Boost Consulting

Boost list run by bdawes at, gregod at, cpdaniel at, john at