Boost logo

Boost :

Subject: Re: [boost] [mpl]iter_fold_if Forward Backward rationale?
From: Larry Evans (cppljevans_at_[hidden])
Date: 2009-04-02 17:16:49


On 04/02/09 14:34, Larry Evans wrote:
> On 03/13/09 18:49, David Abrahams wrote:
[snip]
> Lists can only be constructed backwards because lists don't have a
> push_back? IOW, with only a push_front, the lists have to be
> constructed:
>
> push_front
> < push_front
> < push_front
> < list<>
> , i3
> >
> , i2
> >
> , i1
> >
>
> to create list<i1,i2,i3>? So, a traversal from back to front,
> (i3->i1), is needed, and, for example,
>
> fold<vector<i1,i2,i3>,list<>, push_front<_,_> >
>
> would give:
>
> list<i3,i2,i1>
>
> Instead, to create list<i1,i2,i3> from some sequence, S<i1,i2,i3>,
> reverse_fold would be needed:
>
> reverse_fold<S<i1,i2,i3>,list<>, push_front<_,_> >
>
> Is that about what you mean?
>
[snip]

One reason I'm interested is that I can't figure out how reverse_fold
would work on a sequence, S, such that begin<S>::type with just a
forward iterator. I would have thought that you'd need a
bidirectional iterator in order to traverse backwards; yet:

   https://svn.boost.org/trac/boost/browser/trunk/libs/mpl/test/fold.cpp#L46

shows that it works on lists. Another reason I'm interested is that
both vector and list are implemented using what looks like binary
operators, v_item, and l_item, and I'm wondering why they couldn't be
done with some sort of fold method. After all the vector
super:

   v_item<T_i, vector<T_i-1,T_i-2,...> >

looks like it could be done with a fold. Inspired by that example,
I actually coded one:

-{--code fold_reverse--
   template
   < typename IterNow
   , typename IterEnd
   , typename State
   , typename ForwardOp
   , typename NextOp=next<arg<1> >
>
   struct
fold_reverse_iter
: apply
   < ForwardOp
   , typename fold_reverse_iter
     < typename apply<NextOp,IterNow>::type
     , IterEnd
     , State
     , ForwardOp
     , NextOp
>::type
   , IterNow
>
{
};

   template
   < typename IterEnd
   , typename State
   , typename ForwardOp
   , typename NextOp
>
   struct
fold_reverse_iter
   < IterEnd
   , IterEnd
   , State
   , ForwardOp
   , NextOp
>
{
         typedef
       State
     type
     ;
};

   template
   < class Sequence
   , class State
   , class ForwardOp
>
   struct
fold_reverse
: fold_reverse_iter
   < typename begin<Sequence>::type
   , typename end<Sequence>::type
   , State
   , typename lambda<ForwardOp>::type::template
     apply
     < arg<1>
     , deref<arg<2> >
>
>
{
};

-}--code fold_reverse--

Note how similar it is to the normal fold for the variadic compiler:

-{--code fold--

   template
   < typename IterNow
   , typename IterEnd
   , typename State
   , typename ForwardOp
   , typename NextOp=next<arg<1> >
>
   struct
fold_iter
: fold_iter
   < typename apply<NextOp,IterNow>::type
   , IterEnd
   , typename apply<ForwardOp,State,IterNow>::type
   , ForwardOp
   , NextOp
>
{
};

   template
   < typename IterEnd
   , typename State
   , typename ForwardOp
   , typename NextOp
>
   struct
fold_iter
   < IterEnd
   , IterEnd
   , State
   , ForwardOp
   , NextOp
>
{
         typedef
       State
     type
     ;
};

   template
   < typename Sequence
   , typename State
   , typename ForwardOp
>
   struct
fold
: fold_iter
   < typename begin<Sequence>::type
   , typename end<Sequence>::type
   , State
   , typename lambda<ForwardOp>::type::template
     apply
     < arg<1>
     , deref<arg<2> >
>
>
{
};

-}--code fold--

So, back to v_item and fold_reverse_iter.

The difference is that instead of:

   v_item
   < T0
   , vector<T...>
>

in fold_reverse_iter there's:

   apply
   < ForwardOp
   , typename fold_reverse_iter
     < typename apply<NextOp,IterNow>::type
     , IterEnd
     , State
     , ForwardOp
     , NextOp
>::type
   , IterNow
>

where ForwardOp would be push_front<arg<1>, deref<arg<2> > >.

So, my next question is what's the advantage of using v_item<
vector<T...> > instead of using fold_reverse_iter? I guess you could
say it's more complicated, but then it reuses code and it's not (IMO)
that much more complicated. OTOH, using iter_fold_if is more
complicated and the justification may be that it also reuses code;
however, I'm wondering if it could be simplified by using something
like the fold_reverse_iter.

-regards,
Larry


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