Please help with metaprogramming question : termination of recursion
I'm using Fusion to create a list of Range objects. Here is a simple function: using namespace boost::fusion; template <typename STLCollection, typename FusB, typename FusE> void process_append (STLCollection& collection, const FusB& begin, const FusE& end) { std::cout << "Yip! "; typename result_of::deref<FusB>::type r= deref(begin); /*23*/ collection.insert (collection.end(), boost::begin(r), boost::end(r)); typename result_of::next<FusB>::type successor= next(begin); /*25*/ if (successor != end) process_append (collection, successor, end); std::cout << "Yap! "; } I expect it to print Yip! n times and then Yap! n times. What I get is a compiler error concerning the boost::begin(r) or boost::end(r), that I'm calling it on a fusion::void_ rather than a Range. As you see, I have moved the end-of-recusion test from its normal position at the top of the function (test when called, and return immediately rather than doing the normal body) to the point of the recursive call (don't call with the end sentinel). However, this appears to still trigger the function expansion, since the trail of errors seems to go from the point marked 23 as the original (inner-most) error, to several stops at point 25, to the caller, and so on back out. So it expands several times and then errors, so I think it is objecting to the "end" case. Now if simply mentioning the function, not calling it, is enough to make it expand the function, then more levels of indirection isn't going to help. What is the proper way to do this? Is there, somewhere, a proper example of using Fusion to iterate from begin to end of a Fusion collection? Presumably this must be done using recursion because the type of "next(I)" is not necessarily the same as the type of "I". If some other kind of overloading or partial specialization is the trick, I would expect that the "end" type, or the dereference of the "end" type, would be documented as something I could easily use for that. Please help. Thanks in advance, --John 2>D:\boost_1_43_0\boost/range/iterator.hpp(63) : error C2039: 'type' : is not a member of 'boost::mpl::eval_if_c<C,F1,F2>' 2> with 2> [ 2> C=true, 2> F1=boost::range_const_iterator<boost::fusion::void_>, 2> F2=boost::range_mutable_iterator<const boost::fusion::void_> 2> ] 2> blahblahblah.h(23) : see reference to class template instantiation 'boost::range_iterator<C>' being compiled 2> with 2> [ 2> C=const boost::fusion::void_ 2> ] 2> blahblahblah.h(25) : see reference to function template instantiation 'void Aa::catranges_help::process_append<STLCollection,boost::fusion::cons_iterator<const boost::fusion::nil>,FusE>(STLCollection &,const FusB &,const FusE &)' being compiled 2> with 2> [ 2> STLCollection=std::vector<RTPRICEREC>, 2> FusE=boost::fusion::cons_iterator<const boost::fusion::nil>, 2> FusB=boost::fusion::cons_iterator<const boost::fusion::nil> 2> ] 2> blahblahblah.h(25) : see reference to function template instantiation 'void Aa::catranges_help::process_append<STLCollection,boost::fusion::cons_iterator<Cons>,FusE>(STLCollection &,const FusB &,const FusE &)' being compiled 2> with 2> [ 2> STLCollection=std::vector<RTPRICEREC>, 2> Cons=const boost::fusion::cons<std::pair<std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>>,boost::fusion::nil>, 2> FusE=boost::fusion::cons_iterator<const boost::fusion::nil>, 2> FusB=boost::fusion::cons_iterator<const boost::fusion::cons<std::pair<std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>>,boost::fusion::nil>> 2> ] 2> blahblahblah.h(25) : see reference to function template instantiation 'void Aa::catranges_help::process_append<STLCollection,boost::fusion::cons_iterator<Cons>,FusE>(STLCollection &,const FusB &,const FusE &)' being compiled 2> with 2> [ 2> STLCollection=std::vector<RTPRICEREC>, 2> Cons=const boost::fusion::cons<std::vector<RTPRICEREC>,boost::fusion::cons<std::pair<std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>>,boost::fusion::nil>>, 2> FusE=boost::fusion::cons_iterator<const boost::fusion::nil>, 2> FusB=boost::fusion::cons_iterator<const boost::fusion::cons<std::vector<RTPRICEREC>,boost::fusion::cons<std::pair<std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>>,boost::fusion::nil>>> 2> ] 2> blahblahblah.h(55) : see reference to function template instantiation 'void Aa::catranges_help::process_append<std::vector<_Ty>,boost::fusion::cons_iterator<Cons>,boost::fusion::cons_iterator<const boost::fusion::nil>>(STLCollection &,const FusB &,const FusE &)' being compiled 2> with 2> [ 2> _Ty=RTPRICEREC, 2> Cons=const boost::fusion::cons<std::pair<std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>>,boost::fusion::cons<std::vector<RTPRICEREC>,boost::fusion::cons<std::pair<std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>>,boost::fusion::nil>>>, 2> STLCollection=std::vector<RTPRICEREC>, 2> FusB=boost::fusion::cons_iterator<const boost::fusion::cons<std::pair<std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>>,boost::fusion::cons<std::vector<RTPRICEREC>,boost::fusion::cons<std::pair<std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>>,boost::fusion::nil>>>>, 2> FusE=boost::fusion::cons_iterator<const boost::fusion::nil> 2> ] 2> blahblahblah.h(53) : while compiling class template member function 'Aa::catranges_help::object<R,Tail>::operator std::vector<_Ty>(void) const' 2> with 2> [ 2> R=std::pair<std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>>, 2> TradeStation Group, Inc. is a publicly-traded holding company (NASDAQ GS: TRAD) of three operating subsidiaries, TradeStation Securities, Inc. (Member NYSE, FINRA, SIPC and NFA), TradeStation Technologies, Inc., a trading software and subscription company, and TradeStation Europe Limited, a United Kingdom, FSA-authorized introducing brokerage firm. None of these companies provides trading or investment advice, recommendations or endorsements of any kind. The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer.
I'm using Fusion to create a list of Range objects. Here is a simple function:
using namespace boost::fusion;
template <typename STLCollection, typename FusB, typename FusE> void process_append (STLCollection& collection, const FusB& begin, const FusE& end) { std::cout << "Yip! "; typename result_of::deref<FusB>::type r= deref(begin); /*23*/ collection.insert (collection.end(), boost::begin(r), boost::end(r)); typename result_of::next<FusB>::type successor= next(begin); /*25*/ if (successor != end) process_append (collection, successor, end); std::cout << "Yap! "; }
I expect it to print Yip! n times and then Yap! n times. What I get is a compiler error concerning the boost::begin(r) or boost::end(r), that I'm calling it on a fusion::void_ rather than a Range. As you see, I have moved the end-of-recusion test from its normal position at the top of the function (test when called, and return immediately rather than doing the normal body) to the point of the recursive call (don't call with the end sentinel). However, this appears to still trigger the function expansion, since the trail of errors seems to go from the point marked 23 as the original (inner-most) error, to several stops at point 25, to the caller, and so on back out. So it expands several times and then errors, so I think it is objecting to the "end" case.
Now if simply mentioning the function, not calling it, is enough to make it expand the function, then more levels of indirection isn't going to help. What is the proper way to do this? Is there, somewhere, a proper example of using Fusion to iterate from begin to end of a Fusion collection? Presumably this must be done using recursion because the type of "next(I)" is not necessarily the same as the type of "I".
If some other kind of overloading or partial specialization is the trick, I would expect that the "end" type, or the dereference of the "end" type, would be documented as something I could easily use for that.
You need to decide what function to call based on the _type_ of the fusion iterators: template <typename STLCollection, typename FusB, typename FusE> void process_append (STLCollection& collection, const FusB& begin, const FusE& end, mpl::true_) { // do nothing } template <typename STLCollection, typename FusB, typename FusE> void process_append (STLCollection& collection, const FusB& begin, const FusE& end, mpl::false_) { std::cout << "Yip! "; typename result_of::deref<FusB>::type r= deref(begin); collection.insert (collection.end(), boost::begin(r), boost::end(r)); typename result_of::next<FusB>::type successor= next(begin); process_append (collection, successor, end, is_same< typename result_of::next<FusB>::type, FusE>()); std::cout << "Yap! "; } template <typename STLCollection, typename FusB, typename FusE> void process_append (STLCollection& collection, const FusB& begin, const FusE& end) { process_append(collection, begin, end, is_same<FusB, FusE>()); } Regards Hartmut --------------- Meet me at BoostCon www.boostcon.com
Please help. Thanks in advance,
--John
2>D:\boost_1_43_0\boost/range/iterator.hpp(63) : error C2039: 'type' : is not a member of 'boost::mpl::eval_if_c<C,F1,F2>' 2> with 2> [ 2> C=true, 2> F1=boost::range_const_iterator<boost::fusion::void_>, 2> F2=boost::range_mutable_iterator<const boost::fusion::void_> 2> ] 2> blahblahblah.h(23) : see reference to class template instantiation 'boost::range_iterator<C>' being compiled 2> with 2> [ 2> C=const boost::fusion::void_ 2> ] 2> blahblahblah.h(25) : see reference to function template instantiation 'void Aa::catranges_help::process_append<STLCollection,boost::fusion::cons_itera tor<const boost::fusion::nil>,FusE>(STLCollection &,const FusB &,const FusE &)' being compiled 2> with 2> [ 2> STLCollection=std::vector<RTPRICEREC>, 2> FusE=boost::fusion::cons_iterator<const boost::fusion::nil>, 2> FusB=boost::fusion::cons_iterator<const boost::fusion::nil> 2> ] 2> blahblahblah.h(25) : see reference to function template instantiation 'void Aa::catranges_help::process_append<STLCollection,boost::fusion::cons_itera tor<Cons>,FusE>(STLCollection &,const FusB &,const FusE &)' being compiled 2> with 2> [ 2> STLCollection=std::vector<RTPRICEREC>, 2> Cons=const boost::fusion::cons<std::pair<std::_Vector_const_iterator<RTPRICEREC,std:: allocator<RTPRICEREC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocat or<RTPRICEREC>>>,boost::fusion::nil>, 2> FusE=boost::fusion::cons_iterator<const boost::fusion::nil>, 2> FusB=boost::fusion::cons_iterator<const boost::fusion::cons<std::pair<std::_Vector_const_iterator<RTPRICEREC,std:: allocator<RTPRICEREC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocat or<RTPRICEREC>>>,boost::fusion::nil>> 2> ] 2> blahblahblah.h(25) : see reference to function template instantiation 'void Aa::catranges_help::process_append<STLCollection,boost::fusion::cons_itera tor<Cons>,FusE>(STLCollection &,const FusB &,const FusE &)' being compiled 2> with 2> [ 2> STLCollection=std::vector<RTPRICEREC>, 2> Cons=const boost::fusion::cons<std::vector<RTPRICEREC>,boost::fusion::cons<std::pair< std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>,std::_V ector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>>,boost::fusion ::nil>>,
2> FusE=boost::fusion::cons_iterator<const boost::fusion::nil>, 2> FusB=boost::fusion::cons_iterator<const boost::fusion::cons<std::vector<RTPRICEREC>,boost::fusion::cons<std::pair< std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>,std::_V ector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>>,boost::fusion ::nil>>> 2> ] 2> blahblahblah.h(55) : see reference to function template instantiation 'void Aa::catranges_help::process_append<std::vector<_Ty>,boost::fusion::cons_it erator<Cons>,boost::fusion::cons_iterator<const boost::fusion::nil>>(STLCollection &,const FusB &,const FusE &)' being compiled 2> with 2> [ 2> _Ty=RTPRICEREC, 2> Cons=const boost::fusion::cons<std::pair<std::_Vector_const_iterator<RTPRICEREC,std:: allocator<RTPRICEREC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocat or<RTPRICEREC>>>,boost::fusion::cons<std::vector<RTPRICEREC>,boost::fusion ::cons<std::pair<std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTP RICEREC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC
,boost::fusion::nil>>>, 2> STLCollection=std::vector<RTPRICEREC>, 2> FusB=boost::fusion::cons_iterator<const boost::fusion::cons<std::pair<std::_Vector_const_iterator<RTPRICEREC,std:: allocator<RTPRICEREC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocat or<RTPRICEREC>>>,boost::fusion::cons<std::vector<RTPRICEREC>,boost::fusion ::cons<std::pair<std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTP RICEREC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC ,boost::fusion::nil>>>>, 2> FusE=boost::fusion::cons_iterator<const boost::fusion::nil> 2> ] 2> blahblahblah.h(53) : while compiling class template member function 'Aa::catranges_help::object<R,Tail>::operator std::vector<_Ty>(void) const' 2> with 2> [ 2> R=std::pair<std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICER EC>>,std::_Vector_const_iterator<RTPRICEREC,std::allocator<RTPRICEREC>>>, 2>
TradeStation Group, Inc. is a publicly-traded holding company (NASDAQ GS: TRAD) of three operating subsidiaries, TradeStation Securities, Inc. (Member NYSE, FINRA, SIPC and NFA), TradeStation Technologies, Inc., a trading software and subscription company, and TradeStation Europe Limited, a United Kingdom, FSA-authorized introducing brokerage firm. None of these companies provides trading or investment advice, recommendations or endorsements of any kind. The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer. _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
You need to decide what function to call based on the _type_ of the fusion iterators: process_append(collection, begin, end, is_same<FusB, FusE>());
There is no guarantee that the types will be the same _only_ when it is the end. I'm pretty sure that's the case on a straightforward implementation of 'cons', but what if the iterators are the same type when the dereferenced element is the same type? At the very least, guarantee a unique type for what 'end' is. Now if 'end' is a specific ending type, then I would hope to not need a metafunction to figure it out, but could use some "cons end-of-iteration type" easily obtainable from the cons, as an argument type of 'begin' in an overloaded form of the function. That is, tag "end" types with a base class for that purpose! Thanks for the fast reply! I thought I'd have to come back to it tomorrow. --John TradeStation Group, Inc. is a publicly-traded holding company (NASDAQ GS: TRAD) of three operating subsidiaries, TradeStation Securities, Inc. (Member NYSE, FINRA, SIPC and NFA), TradeStation Technologies, Inc., a trading software and subscription company, and TradeStation Europe Limited, a United Kingdom, FSA-authorized introducing brokerage firm. None of these companies provides trading or investment advice, recommendations or endorsements of any kind. The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer.
You need to decide what function to call based on the _type_ of the fusion iterators: process_append(collection, begin, end, is_same<FusB, FusE>());
There is no guarantee that the types will be the same _only_ when it is the end. I'm pretty sure that's the case on a straightforward implementation of 'cons', but what if the iterators are the same type when the dereferenced element is the same type? At the very least, guarantee a unique type for what 'end' is.
Now if 'end' is a specific ending type, then I would hope to not need a metafunction to figure it out, but could use some "cons end-of-iteration type" easily obtainable from the cons, as an argument type of 'begin' in an overloaded form of the function. That is, tag "end" types with a base class for that purpose!
Thanks for the fast reply! I thought I'd have to come back to it tomorrow.
Fusion iterators are unique regardless of the type of the value they dereference to. If you look at how the Fusion algorithms are implemented you'll see that there the same trick is utilized. Regards Hartmut --------------- Meet me at BoostCon www.boostcon.com
Fusion iterators are unique regardless of the type of the value they dereference to. If you look at how the Fusion algorithms are implemented you'll see that there the same trick is utilized.
Unique in every location in every collection is a distinct type? This could be documented somewhere <grumbling>. Or maybe, to make the trick work, "end" is a unique type regardless. And, his equal_to for iterators works, even if is_same isn't. BTW, are you familiar with how MPL and other boost libraries interoperate with the native TR1 support? It's not nice to have different sets of type_traits and true/false values, and I would want new code to support some trait-like things using the new standard. --John TradeStation Group, Inc. is a publicly-traded holding company (NASDAQ GS: TRAD) of three operating subsidiaries, TradeStation Securities, Inc. (Member NYSE, FINRA, SIPC and NFA), TradeStation Technologies, Inc., a trading software and subscription company, and TradeStation Europe Limited, a United Kingdom, FSA-authorized introducing brokerage firm. None of these companies provides trading or investment advice, recommendations or endorsements of any kind. The information transmitted is intended only for the person or entity to which it is addressed and may contain confidential and/or privileged material. Any review, retransmission, dissemination or other use of, or taking of any action in reliance upon, this information by persons or entities other than the intended recipient is prohibited. If you received this in error, please contact the sender and delete the material from any computer.
On 7/9/10 8:54 AM, Hartmut Kaiser wrote:
You need to decide what function to call based on the _type_ of the fusion iterators: process_append(collection, begin, end, is_same<FusB, FusE>());
There is no guarantee that the types will be the same _only_ when it is the end. I'm pretty sure that's the case on a straightforward implementation of 'cons', but what if the iterators are the same type when the dereferenced element is the same type? At the very least, guarantee a unique type for what 'end' is.
Now if 'end' is a specific ending type, then I would hope to not need a metafunction to figure it out, but could use some "cons end-of-iteration type" easily obtainable from the cons, as an argument type of 'begin' in an overloaded form of the function. That is, tag "end" types with a base class for that purpose!
Thanks for the fast reply! I thought I'd have to come back to it tomorrow.
Fusion iterators are unique regardless of the type of the value they dereference to. If you look at how the Fusion algorithms are implemented you'll see that there the same trick is utilized.
John, don't think in terms of Cons. Think in terms of Fusion iterators. See the fusion for_each implementation for inspiration. Regards, -- Joel de Guzman http://www.boostpro.com http://spirit.sf.net
AMDG Hartmut Kaiser wrote:
template <typename STLCollection, typename FusB, typename FusE> void process_append (STLCollection& collection, const FusB& begin, const FusE& end, mpl::false_) { std::cout << "Yip! "; typename result_of::deref<FusB>::type r= deref(begin); collection.insert (collection.end(), boost::begin(r), boost::end(r)); typename result_of::next<FusB>::type successor= next(begin); process_append (collection, successor, end, is_same< typename result_of::next<FusB>::type, FusE>());
Doens't fusion use fusion::equal_to instead of is_same? In Christ, Steven Watanabe
Hartmut Kaiser wrote:
template <typename STLCollection, typename FusB, typename FusE> void process_append (STLCollection& collection, const FusB& begin, const FusE& end, mpl::false_) { std::cout << "Yip! "; typename result_of::deref<FusB>::type r= deref(begin); collection.insert (collection.end(), boost::begin(r), boost::end(r)); typename result_of::next<FusB>::type successor= next(begin); process_append (collection, successor, end, is_same< typename result_of::next<FusB>::type, FusE>());
Doens't fusion use fusion::equal_to instead of is_same?
Indeed. Sorry for being inconcise. Regards Hartmut --------------- Meet me at BoostCon www.boostcon.com
participants (4)
-
Hartmut Kaiser
-
Joel de Guzman
-
John Dlugosz
-
Steven Watanabe