[Range] Select forward or reverse traversal at compile time?
Given a bidirectional range R, is it possible to select at compile time whether we want to iterate forwards or backwards? Below is a test app. At the commented line, I would like to transparently construct a forward or reverse range, ie either [begin(range), end(range)] or [rbegin(range), rend(range)] respectively, depending on the definition of the Reversed template parameter. Just to be clear, the desired output is: forward: abc reversed: abc I can make this work by using a functor class with partial specialisation to construct the iterator_range, using begin/end or rbegin/rend respectively. But it's a bit ugly and it would seem like something that boost range would provide anyway? (Note that boost::reverse() is NOT what I am after.) #include <boost/assign/list_of.hpp> #include <boost/range/algorithm/copy.hpp> #include <boost/range.hpp> #include <vector> #include <iostream> template <typename Reversed, typename Range> std::string Print(const Range& range) { typedef boost::iterator_range< typename boost::mpl::eval_if< Reversed, boost::range_reverse_iterator<const Range>, boost::range_iterator<const Range> >::type> IterRange; // want to convert it to a forward range here IterRange forwardRange(range); std::string result; boost::copy(forwardRange, std::back_inserter(result)); return result; } int main(int argc, char* argv[]) { using boost::assign::list_of; std::vector<char> a = list_of('a')('b')('c'); std::vector<char> b = list_of('c')('b')('a'); std::cout << "forward: " << Print<boost::mpl::false_>(a) << std::endl << "reversed: " << Print<boost::mpl::true_>(b) << std::endl; return 0; }
On Wed, Jun 29, 2011 at 1:19 PM, Alastair Rankine <arsptr@internode.on.net>wrote:
Given a bidirectional range R, is it possible to select at compile time whether we want to iterate forwards or backwards?
Below is a test app. At the commented line, I would like to transparently construct a forward or reverse range, ie either [begin(range), end(range)] or [rbegin(range), rend(range)] respectively, depending on the definition of the Reversed template parameter.
Just to be clear, the desired output is:
forward: abc reversed: abc
Surely you mean ha the reversed output would be: cba ?
I can make this work by using a functor class with partial specialisation to construct the iterator_range, using begin/end or rbegin/rend respectively. But it's a bit ugly and it would seem like something that boost range would provide anyway?
(Note that boost::reverse() is NOT what I am after.)
What you are looking for is a reversing adaptor, hence you probably should look at boost::adaptors::reversed, please see http://www.boost.org/doc/libs/1_46_1/libs/range/doc/html/range/reference/ada.... Note that you could also use the reversed_range class directly. Regards, Neil Groves
On 30/06/11 02:32, Neil Groves wrote:
On Wed, Jun 29, 2011 at 1:19 PM, Alastair Rankine <arsptr@internode.on.net <mailto:arsptr@internode.on.net>> wrote: Just to be clear, the desired output is:
forward: abc reversed: abc
Surely you mean ha the reversed output would be: cba ?
No - the point is that I want to be able to specify at compile time (via the Reversed template argument) whether or not the range should be processed in reverse order. In the above example "reversed" refers to an array "cba" which has Reversed set to a true type, meaning that it should be processed in the reverse direction, producing "abc" Hope that is clear?
What you are looking for is a reversing adaptor, hence you probably should look at boost::adaptors::reversed, please see http://www.boost.org/doc/libs/1_46_1/libs/range/doc/html/range/reference/ada....
No, the reversing adaptor doesn't work either. Remember I want to specify *at compile time* whether or not to reverse the range. If hypothetically there was a "null" range adapter, I could do something like: typedef boost::mpl::if_<Reversed, boost::adaptors::reversed, boost::adaptors::null>::type adaptor; boost::copy( adaptor(range) , ...); But that doesn't seem to exist either.
Note that you could also use the reversed_range class directly.
I make a point of never using anything in a detail namespace unless absolutely necessary. But even in this case I don't think it will help.
What you are looking for is a reversing adaptor, hence you probably should look at boost::adaptors::reversed, please see http://www.boost.org/doc/libs/1_46_1/libs/range/doc/html/range/reference/ada....
No, the reversing adaptor doesn't work either. Remember I want to specify *at compile time* whether or not to reverse the range.
If hypothetically there was a "null" range adapter, I could do something like:
typedef boost::mpl::if_<Reversed, boost::adaptors::reversed, boost::adaptors::null>::type adaptor;
boost::copy( adaptor(range) , ...);
But that doesn't seem to exist either.
The Pstade Oven library (a Boost.Range extension library) has an "identity" adaptor: http://p-stade.sourceforge.net/oven/doc/html/oven/range_adaptors.html#oven.r... This library may one day become part of Boost.Range. Nate.
What you are looking for is a reversing adaptor, hence you probably
should look at boost::adaptors::reversed, please see http://www.boost.org/doc/libs/**1_46_1/libs/range/doc/html/** range/reference/adaptors/**reference/reversed.html<http://www.boost.org/doc/libs/1_46_1/libs/range/doc/html/range/reference/adaptors/reference/reversed.html> .
No, the reversing adaptor doesn't work either. Remember I want to specify *at compile time* whether or not to reverse the range.
Not only does the reverse adaptor work it can easily address your stated problem.Like this: template<typename RangeT, typename Cond> struct conditional_reverse_type_generator { typedef typename boost::mpl::if_< Cond, boost::reversed_range<RangeT>, boost::sub_range<RangeT> >::type type; }; template<typename Cond, typename RangeT> inline typename conditional_reverse_type_generator<RangeT,Cond>::type conditional_reverse(RangeT& rng) { typedef typename conditional_reverse_type_generator<RangeT,Cond>::type result_type; return result_type(rng); } template<typename Cond, typename RangeT> inline typename conditional_reverse_type_generator<const RangeT,Cond>::type conditional_reverse(const RangeT& rng) { typedef typename conditional_reverse_type_generator<const RangeT,Cond>::type result_type; return result_type(rng); }
If hypothetically there was a "null" range adapter, I could do something like:
typedef boost::mpl::if_<Reversed, boost::adaptors::reversed, boost::adaptors::null>::type adaptor;
boost::copy( adaptor(range) , ...);
But that doesn't seem to exist either.
I have never had the need for a null adaptor, and this would be the first request. I shall implement one for a later version of Boost since I can see a few use cases. However you need not wait, and I don't think it provides a better solution to your problem.
Note that you could also use the reversed_range class directly.
It is implemented in a detail namespace, but is brought into the boost namespace. This changed from the first versions of Boost.Range with adaptors. By popular demand the return types of the adaptors are now all public documented types.
I make a point of never using anything in a detail namespace unless absolutely necessary. But even in this case I don't think it will help.
You don't need to use anything in a detail namespace, and it does help ;-) Regards, Neil Groves
On 01/07/11 08:02, Neil Groves wrote:
Not only does the reverse adaptor work it can easily address your stated problem.Like this:
Well technically the reverse_range type does solve the problem, the reverse adaptor doesn't. But yes I can confirm that your conditional_reverse does prettymuch exactly what I want.
Note that you could also use the reversed_range class directly.
It is implemented in a detail namespace, but is brought into the boost namespace. This changed from the first versions of Boost.Range with adaptors. By popular demand the return types of the adaptors are now all public documented types.
My mistake, I see that reverse_range is a public type. However I would suggest that the documentation is less than entirely clear on this class. As far as I can tell, reverse_range is only mentioned in the documentation as a return type of the reversed range adaptor, and there is no other information about it. Furthermore I think you have shown that reverse_range has utility in its own right, and hence should be implemented in a separate header from the reversed range adaptor? Thanks for your help.
participants (3)
-
Alastair Rankine
-
Nathan Ridge
-
Neil Groves