Boost logo

Boost :

From: Richard Crossley (rdc_at_[hidden])
Date: 2002-09-19 10:37:38


> > How would this work with, for example the traits classes, assuming
> > that for consistency they also evaluate their arguments?
> Would we now
> > have to write remove_pointer<identity<char*> >::type or would the
> > traits classes be specialised in some way for the built in types?
>
> Yeah. That's one issue with this.
>
> > Personally I 'get around the problem' with an additional template:
> >
> > template <typename T>
> > struct eva; // evaluate arguments
> > etc... So,

[snip]

> >
> > apply_if<some_condition,
> > some_type_1,
> > plus<some_type_2::type,some_number >
> > >::type;
> >
> > Becomes,
> >
> > apply_if<some_condition,
> > some_type_1,
> > eva<plus,some_type_2,some_number>
> > >::type;
> >
> > Assuming some_number evaluates to its self, or if not,
> >
> > apply_if<some_condition,
> > some_type_1,
> > eva<plus,some_type_2,identity<some_number> >
> >::type;
>
> (By the way, I assume there should be a ",", rather than "<",
> after "plus" above, so I've changed that in the quote above)

No, the original was correct. Note that eva is always specialised and
only accepts a single parameter :-)

> One advantage of this solution is that it works with MPL as it is.

> Consider the "factorial" metafunction, again:
>
> template<class V>
> struct factorial
> {
> typedef typename V::type Value;
>
> typedef typename apply_if<equal_to<Value,value<Value,0> >,
> value<Value,1>,
> mul<Value,factorial<prior<Value> > >
> >::type type;
> }
>
> I had first planned to look at a comparison with using "eva,"
> but I realized that I had a hard time finding out how I could
> write the above, using "eva," since the call to factorial is
> used as a parameter to "mul," and unlike apply_if, that
> doesn't evaluate its arguments, which is what makes your
> first "eva" example work.
>
> Could you have shown how I could rewrite the above, using "eva"?

In a sort of MPL psuedo-code :-) but I think you can see whats
happening:

template <typename N = _>
struct factorial : apply_if<equal_to<N,int_c<1>
>,N,eva<mul<eva<factorial<prior<N> > >,N> > >{};

>
> Unless there's something obvious I've missed, I think the
> fact that it's hard to write one of the simplest
> metafunctions, factorial, using "eva," could mean that it
> could be hard to use this solution.

Doesn't look difficult to me but that may just be familiarity with eva.

Taking it a bit further something like this could be used:

template <typename T>
struct id{typedef T type;};

template <typename T>
struct eval{typedef T::type type;};

template <typename T>
struct eval<id<T> > : id<T>{};

template <template <typename> class F,typename A0>
struct eval<F<A0> > : F<typename eval<A0>::type>{};

template <template <typename,typename> class F,typename A0,typename A1>
struct eval<F<A0,A1> > : F<typename eval<A0>::type,typename
eval<A1>::type>{};

Etc...

template <typename N = _>
struct factorial : apply_if<equal_to<N,int_c<1>
>,N,eval<mul<factorial<prior<N> >,N> > >{};

> Regarding your first comment, about the type traits, that's a
> legitimate issue. Perhaps an exception could be made for
> them. You might also, as you say, specialise for built-in
> types. This is an open issue. However, I feel the advantage
> in having metafunctions evaluate their own arguments is so
> great, that it should be possible to find a solution to this.
> Besides not having to split the code up, I feel it becomes
> cleaner, when you don't have to have all those "::type" in
> the code. After all, run-time programming doesn't use named
> return values, either (similar to the "::type"). Consider the
> following line (ignoring for a moment that the "::type"
> solution doesn't work, but you would have to have something
> there, anyway, such as "eva"):
>
> mul<Value,factorial<prior<Value> > >
>
> compared to:
>
> mul<Value,factorial<prior<Value>::type>::type>

eval<mul<Value,factorial<prior<Value> > > >

Richard.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk