best way to make {reverse_}fold a sequence

After creating: typedef range_c<int,0,3> types; typedef fold < types , empty_base , inherit< arg<2>, arg<1> > >::type tuple_type; I'd like to use for_each on tuple_type. For example: struct print_integral_c { template<int i, typename Right> void operator()(inherit<integral_c<int,i>, Right>)const { std::cout<<i<<"\n"; } }; for_each<tuple_type>(print_integral_c); However, tuple_type is not a sequence; hence, for_each won't work. I could define the necessary specializations for mpl::begin, etc., to make it a sequence, but I was wondering if there's any way or any plans to somehow automagically make fold or reverse_fold into a sequence so I could use for_each on it.

Larry Evans <cppljevans@cox-internet.com> writes:
After creating:
typedef range_c<int,0,3> types; typedef fold < types , empty_base , inherit< arg<2>, arg<1> > >::type tuple_type;
I'd like to use for_each on tuple_type. For example:
struct print_integral_c { template<int i, typename Right> void operator()(inherit<integral_c<int,i>, Right>)const { std::cout<<i<<"\n"; } };
for_each<tuple_type>(print_integral_c);
However, tuple_type is not a sequence; hence, for_each won't work. I could define the necessary specializations for mpl::begin, etc., to make it a sequence, but I was wondering if there's any way or any plans to somehow automagically make fold or reverse_fold into a sequence so I could use for_each on it.
No. Since fold and reverse_fold are metafunctions (and therefore class templates), they can't possibly be sequences (which are always types). fold and reverse_fold don't even have to _return_ sequences. I can't understand why you're not using Fusion, or at least trying to fit into the Fusion framework, but I'm going to stop flogging that horse now. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On 02/28/2005 01:56 AM, David Abrahams wrote:
Larry Evans <cppljevans@cox-internet.com> writes:
After creating:
typedef range_c<int,0,3> types; typedef fold < types , empty_base , inherit< arg<2>, arg<1> > >::type tuple_type;
I'd like to use for_each on tuple_type. For example:
struct print_integral_c { template<int i, typename Right> void operator()(inherit<integral_c<int,i>, Right>)const { std::cout<<i<<"\n"; } };
for_each<tuple_type>(print_integral_c);
However, tuple_type is not a sequence; hence, for_each won't work. I could define the necessary specializations for mpl::begin, etc., to make it a sequence, but I was wondering if there's any way or any plans to somehow automagically make fold or reverse_fold into a sequence so I could use for_each on it.
No. Since fold and reverse_fold are metafunctions (and therefore class templates), they can't possibly be sequences (which are always types). fold and reverse_fold don't even have to _return_ sequences.
From my OP, the sentence: tuple_type is not a sequence; I thought would make it obvious that I didn't mean the metafunction, but the result of invokation of that metafunction. OTOH, I really should have said "make the result of a fold metafunction invokation into a sequence". Would that have been sufficient to make my meaning clear?
I can't understand why you're not using Fusion, or at least trying to fit into the Fusion framework, but I'm going to stop flogging that horse now.
IIUC, Fusion is in flux, based on the post: http://article.gmane.org/gmane.comp.lib.boost.devel/118011 and mpl has an easy to use reference manual: http://www.boost.org/libs/mpl/doc/refmanual/refmanual_toc.html OTOH, I haven't really looked at fusion, so maybe I should. It's just I've found mpl very good and I've gotten used to it; hence, I'm reluctant to change. I'll take a closer look at fusion and see if I can get it to work, but It's got to do the range_all http://article.gmane.org/gmane.comp.lib.boost.devel/117764 "thing" also, and I had some difficulty getting that to work with mpl; hence, I don't want to go thru that again with fusion, so, no promises. BTW, the range_all.zip has moved in the vault to cppljevans/mpl.

Larry Evans <cppljevans@cox-internet.com> writes:
On 02/28/2005 01:56 AM, David Abrahams wrote:
Larry Evans <cppljevans@cox-internet.com> writes:
After creating:
typedef range_c<int,0,3> types; typedef fold < types , empty_base , inherit< arg<2>, arg<1> > >::type tuple_type;
I'd like to use for_each on tuple_type. For example:
struct print_integral_c { template<int i, typename Right> void operator()(inherit<integral_c<int,i>, Right>)const { std::cout<<i<<"\n"; } };
for_each<tuple_type>(print_integral_c);
However, tuple_type is not a sequence; hence, for_each won't work. I could define the necessary specializations for mpl::begin, etc., to make it a sequence, but I was wondering if there's any way or any plans to somehow automagically make fold or reverse_fold into a sequence so I could use for_each on it. No. Since fold and reverse_fold are metafunctions (and therefore class templates), they can't possibly be sequences (which are always types). fold and reverse_fold don't even have to _return_ sequences.
From my OP, the sentence:
tuple_type is not a sequence;
I thought would make it obvious that I didn't mean the metafunction, but the result of invokation of that metafunction.
OTOH, I really should have said "make the result of a fold metafunction invokation into a sequence". Would that have been sufficient to make my meaning clear?
Not really. As I said, "fold and reverse_fold don't even have to _return_ sequences." By that I mean that the result of invoking fold might be, e.g. int.
I can't understand why you're not using Fusion, or at least trying to fit into the Fusion framework, but I'm going to stop flogging that horse now.
IIUC, Fusion is in flux, based on the post:
http://article.gmane.org/gmane.comp.lib.boost.devel/118011
and mpl has an easy to use reference manual:
http://www.boost.org/libs/mpl/doc/refmanual/refmanual_toc.html
OTOH, I haven't really looked at fusion, so maybe I should. It's just I've found mpl very good and I've gotten used to it; hence, I'm reluctant to change.
It's not a change. Fusion is a compatible layer on top of MPL. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On 02/28/2005 07:16 AM, David Abrahams wrote: [snip]
OTOH, I really should have said "make the result of a fold metafunction invokation into a sequence". Would that have been sufficient to make my meaning clear?
Not really. As I said, "fold and reverse_fold don't even have to _return_ sequences." By that I mean that the result of invoking fold might be, e.g. int.
OK, granted, but I need it to be a sequence. I guess what I planned will not work on all results of fold, but it will work on at least some. Right now, I'm just trying to get it to work on what I need at the moment, which is part of a test driver. I guess I'll just write my own begin<fold<Sequence,StartState,ForwardOp> > and put it in my test driver directory. [snip]
OTOH, I haven't really looked at fusion, so maybe I should. It's just I've found mpl very good and I've gotten used to it; hence, I'm reluctant to change.
It's not a change. Fusion is a compatible layer on top of MPL.
My other post mentioned visitors.hpp and its need for fold. How could fusion's tuple be used to implement visitors where the critical need is a StartState superclass for all instantiations of ForwardOp?

Larry Evans <cppljevans@cox-internet.com> writes:
On 02/28/2005 07:16 AM, David Abrahams wrote: [snip]
OTOH, I really should have said "make the result of a fold metafunction invokation into a sequence". Would that have been sufficient to make my meaning clear? Not really. As I said, "fold and reverse_fold don't even have to _return_ sequences." By that I mean that the result of invoking fold might be, e.g. int.
OK, granted, but I need it to be a sequence. I guess what I planned will not work on all results of fold, but it will work on at least some. Right now, I'm just trying to get it to work on what I need at the moment, which is part of a test driver. I guess I'll just write my own begin<fold<Sequence,StartState,ForwardOp> > and put it in my test driver directory.
That's misguided it seems to me. Your tuple_type is not a specialization of fold. Are you really interested in making specializations of fold into sequences? You're folding some kind of cons cell, right? Don't you want to implement begin and end on that? template <class A, class B> struct begin<inherit<A,B> > { ... }; or something?
[snip]
OTOH, I haven't really looked at fusion, so maybe I should. It's just I've found mpl very good and I've gotten used to it; hence, I'm reluctant to change.
It's not a change. Fusion is a compatible layer on top of MPL.
My other post mentioned visitors.hpp and its need for fold. How could fusion's tuple be used to implement visitors where the critical need is a StartState superclass for all instantiations of ForwardOp?
I'm not the guy to ask, sorry. Joel is the fusion expert, and... I mean no offense by this, but I find your code hard to read and understand, so I'm trying to be helpful while not getting entangled in looking at its details because I think it will cost me too much time. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On 02/28/2005 10:01 AM, David Abrahams wrote: [snip]
That's misguided it seems to me. Your tuple_type is not a specialization of fold. Are you really interested in making specializations of fold into sequences?
You're folding some kind of cons cell, right? Don't you want to implement begin and end on that?
template <class A, class B> struct begin<inherit<A,B> > { ... };
or something? Yes. But how do I know what A or B is. It has to be the result of size<Sequence>-1 applications of ForwardOp. Is there a way to get this other than fold<Sequence,StartState,ForwardOp>::type ? Hmmm. This is what get_side_type does with Index == 0. Maybe I could use that.
BTW, get_side_type is also in vault. [snip]
My other post mentioned visitors.hpp and its need for fold. How could fusion's tuple be used to implement visitors where the critical need is a StartState superclass for all instantiations of ForwardOp?
I'm not the guy to ask, sorry. Joel is the fusion expert, and... I mean no offense by this, but I find your code hard to read and understand, so I'm trying to be helpful while not getting entangled in looking at its details because I think it will cost me too much time.
OK. Thanks for the help :)

Larry Evans <cppljevans@cox-internet.com> writes:
On 02/28/2005 10:01 AM, David Abrahams wrote: [snip]
That's misguided it seems to me. Your tuple_type is not a specialization of fold. Are you really interested in making specializations of fold into sequences? You're folding some kind of cons cell, right? Don't you want to implement begin and end on that? template <class A, class B> struct begin<inherit<A,B> > { ... }; or something?
Yes. But how do I know what A or B is.
?? At the point of ... the compiler knows what they are
It has to be the result of size<Sequence>-1 applications of ForwardOp.
Do you mean that you want to restrict the partial specialization matching to only match your tuple types? You don't have to use inherit directly, you know; you could just derive your own my_inherit class from it and match that in the partial specialization. If you only use my_inherit to build these tuples, you're home free. -- Dave Abrahams Boost Consulting www.boost-consulting.com

On 02/28/2005 06:35 PM, David Abrahams wrote:
Larry Evans <cppljevans@cox-internet.com> writes:
On 02/28/2005 10:01 AM, David Abrahams wrote: [snip]
You're folding some kind of cons cell, right? Don't you want to implement begin and end on that? template <class A, class B> struct begin<inherit<A,B> > { ... }; or something?
Yes. But how do I know what A or B is.
??
At the point of ... the compiler knows what they are
So, I tried: //{--------- cut-here -------- template < template<typename,typename>class ForwardOpTmpl , typename LeftArg , typename RightArg
struct begin < ForwardOpTmpl<LeftArg,RightArg> > { typedef ForwardOpTmpl<LeftArg,RightArg> type; }; template < template<typename,typename>class ForwardOpTmpl , typename LeftArg , typename RightArg
struct next < ForwardOpTmpl<LeftArg,RightArg> > { typedef RightArg type; }; //}--------- cut-here -------- But intel-linux said next was ambiguous. Also, the above code assumes the last arg to fold was: ForwardOpTmpl<arg<2>,arg<1> > I was hoping to be more general, but maybe just for my test, it would be OK.
It has to be the result of size<Sequence>-1 applications of ForwardOp.
Do you mean that you want to restrict the partial specialization matching to only match your tuple types? You don't have to use inherit directly, you know; you could just derive your own my_inherit class from it and match that in the partial specialization. If you only use my_inherit to build these tuples, you're home free.
Replacing ForwardOpTmpl with my_inherit, defined as: template< typename Left, typename Right> struct my_inherit: inherit2<Left,Right> { typedef my_inherit type; }; still got the ambiguous error message with intel-linux. gcc gave some other error message. Even if the above did, work, I'd need an end specialization, and that would involve knowing the 2nd arg to fold; hence, the specialization would have to be: template<typename Sequence, typename Start, typename ForwardOp> struct end<fold<Sequence,Start,ForwardOp>::type> { ... }; which is doomed to fail (AFAICT) because of the non-deduced context. Or am I missing something again?

Larry Evans <cppljevans@cox-internet.com> writes:
On 02/28/2005 06:35 PM, David Abrahams wrote:
Larry Evans <cppljevans@cox-internet.com> writes:
On 02/28/2005 10:01 AM, David Abrahams wrote: [snip]
You're folding some kind of cons cell, right? Don't you want to implement begin and end on that? template <class A, class B> struct begin<inherit<A,B> > { ... }; or something?
Yes. But how do I know what A or B is. ?? At the point of ... the compiler knows what they are
So, I tried: //{--------- cut-here -------- template < template<typename,typename>class ForwardOpTmpl , typename LeftArg , typename RightArg
struct begin < ForwardOpTmpl<LeftArg,RightArg> > { typedef ForwardOpTmpl<LeftArg,RightArg> type; };
Of course that is way too general. Not every template that might match is meant to be a sequence. (Also: do you really mean your sequence iterators to be the same type as the sequence itself?)
template < template<typename,typename>class ForwardOpTmpl , typename LeftArg , typename RightArg
struct next < ForwardOpTmpl<LeftArg,RightArg> > { typedef RightArg type; }; //}--------- cut-here -------- But intel-linux said next was ambiguous.
As above, too general, but I'm curious anyway: ambiguous with what? A single declaration can't be ambiguous with itself.
Also, the above code assumes the last arg to fold was:
ForwardOpTmpl<arg<2>,arg<1> >
No it doesn't. The last arg to fold has nothing to do with it. It might have been a metafunction class. In fact, fold has nothing to do with it. The above code tries to make all type structures built on two-element class templates look like sequences. But it's too general and assumes way too much. For example, the structure might be a tree.
I was hoping to be more general, but maybe just for my test, it would be OK.
!? *More* general? That's definitely going down the wrong road.
It has to be the result of size<Sequence>-1 applications of ForwardOp.
Do you mean that you want to restrict the partial specialization matching to only match your tuple types? You don't have to use inherit directly, you know; you could just derive your own my_inherit class from it and match that in the partial specialization. If you only use my_inherit to build these tuples, you're home free.
Replacing ForwardOpTmpl with my_inherit, defined as:
template< typename Left, typename Right> struct my_inherit: inherit2<Left,Right> { typedef my_inherit type; };
still got the ambiguous error message with intel-linux.
Well of course it did. Just as declaring a class template called ForwardOpTmpl before writing your begin and next above wouldn't have changed anything either. template <class Left, class Right> struct next<my_inherit<Left,Right> > { // ... whatever }; would be more appropriate.
gcc gave some other error message.
Even if the above did, work, I'd need an end specialization, and that would involve knowing the 2nd arg to fold;
Again, fold has nothing to do with it.
hence, the specialization would have to be:
template<typename Sequence, typename Start, typename ForwardOp> struct end<fold<Sequence,Start,ForwardOp>::type> { ... };
which is doomed to fail (AFAICT) because of the non-deduced context.
Or am I missing something again?
Forget about fold. It's just a metafunction that _you_ happen to be using to build the eventual sequence type. The fold algorithm has nothing to do with building sequences, intrinsically, just as std::accumulate (its analogue) has nothing to do with any particular job. You need to focus on the class of types that gets built by your code and stop looking at fold. -- Dave Abrahams Boost Consulting www.boost-consulting.com

Thanks for the help, David. On 03/01/2005 08:25 AM, David Abrahams wrote: [snip]
Of course that is way too general. Not every template that might match is meant to be a sequence.
OK, but I just want it to work with my fold<...>::type, and making it as general as possible seemed the fasted way to just get a compile to work.
(Also: do you really mean your sequence iterators to be the same type as the sequence itself?)
It doesn't really matter to me as long as I get a clean compile and some result from deref that I can use. If the deref<...>::type is inherit2<Left,Right>, then I can always get the Left or Right parts with another template specialization.
template < template<typename,typename>class ForwardOpTmpl , typename LeftArg , typename RightArg
struct next < ForwardOpTmpl<LeftArg,RightArg> > { typedef RightArg type; }; //}--------- cut-here -------- But intel-linux said next was ambiguous.
As above, too general, but I'm curious anyway: ambiguous with what? A single declaration can't be ambiguous with itself.
I was unclear. The error message was about next: fold_sequence_test.cpp(98): error: "next" is ambiguous typedef next<iter0>::type iter1; ^ See the http://boost-sandbox.sourceforge.net/vault/ in cppljevans/mpl/fold_sequence.zip. The compiler error messages included in this zip only include the 1st error message. The above can be seen by simply mv'ing the nearby #if 0 down past the above statement and compiling.
Also, the above code assumes the last arg to fold was:
ForwardOpTmpl<arg<2>,arg<1> >
No it doesn't. The last arg to fold has nothing to do with it. It might have been a metafunction class. In fact, fold has nothing to do with it.
Well, I've got to know the place_holder arg order in order to know whether next should return the Left or right part of my_inherit<L,R>. [snip]
!? *More* general? That's definitely going down the wrong road.
Yes, but for right now, I just want a compile the works on the simplest type of Sequence arg to fold. [snip]
template <class Left, class Right> struct next<my_inherit<Left,Right> > { // ... whatever };
would be more appropriate.
The fold_sequence_test.zip referred to above does this, but with inherit2 instead of my_inherit; yet, it still get's a compile error, as shown by the fold_sequence_test.intel within the zip.

On 03/01/2005 03:00 PM, Larry Evans wrote: [snip]
I was unclear. The error message was about next:
fold_sequence_test.cpp(98): error: "next" is ambiguous typedef next<iter0>::type iter1; ^ See the http://boost-sandbox.sourceforge.net/vault/ in cppljevans/mpl/fold_sequence.zip. The compiler error messages included in this zip only include the 1st error message.
The 1st error message in fold_sequence.zip, dealing with begin, was avoided by defining my_inherit2 with a nested type. typedef my_inherit2 type; However, the ambiguous error, concerning next, is still around, as shown by fold_sequence_test1.zip in the vault.

On 03/01/2005 03:23 PM, Larry Evans wrote: [snip]
However, the ambiguous error, concerning next, is still around, as shown by fold_sequence_test1.zip in the vault.
The ambiguous error was removed by removing the using namespace boost::mpl; statement and prefixing all the mpl names with mpl:: .

On 03/01/2005 08:25 AM, David Abrahams wrote: [snip]
template<typename Sequence, typename Start, typename ForwardOp> struct end<fold<Sequence,Start,ForwardOp>::type> { ... };
which is doomed to fail (AFAICT) because of the non-deduced context.
Or am I missing something again?
Forget about fold. It's just a metafunction that _you_ happen to be using to build the eventual sequence type. The fold algorithm has nothing to do with building sequences, intrinsically, just as std::accumulate (its analogue) has nothing to do with any particular job. You need to focus on the class of types that gets built by your code and stop looking at fold.
The code in vault under cppljevans/mpl/fold_sequence4.zip works for gcc, and the intel problem is due to an intel bug AFAICT. This bug has been reported to intel as issue 287414. The workaround is just to define: template<class Left,class Right> void print_integral_c::operator()(my_node<Left,Right>)const {...}

On 02/28/2005 01:56 AM, David Abrahams wrote:
types). fold and reverse_fold don't even have to _return_ sequences.
Which is what I'm trying to remedy. I need this because I would like to use for_each on the result of a fold invokation.
I can't understand why you're not using Fusion, or at least trying to fit into the Fusion framework
Maybe the visitor.hpp in sand-box vault will illustrate. I found it convenient to define field_sets, and then make it the base class of visits_fields<VisitorId> for VisitorId in visitor_numerals (an enumeration). IIUC, fusion tuples, if it's like the existing boost tuple, takes a sequence of types and produces a type; yet, that wouldn't make field_sets the base type. I need something where the base type (corresponding to the default empty_base for inherit_linearly), is user-specified, and tuples doesn't work.
participants (2)
-
David Abrahams
-
Larry Evans