Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Using range-based for with alternative ranges

18 views
Skip to first unread message

Juha Nieminen

unread,
May 18, 2012, 1:20:41 PM5/18/12
to
I was thinking: How hard would it be to use the range-based for syntax
for ranges other than the full begin-end range. For instance, what if
you wanted it to traverse the container backwards instead of forwards?

What I mean is that one could write something like this:

//------------------------------------------------------------------
int table[] = { 1, 3, 5, 7, 9 };
std::vector<int> v(table, std::end(table));

std::cout << "Forwards:\n";

for(int element: table) std::cout << " " << element;
for(int element: v) std::cout << " " << element;

std::cout << "\nBackwards:\n";

for(int element: reverseRange(table)) std::cout << " " << element;
for(int element: reverseRange(v)) std::cout << " " << element;

std::cout << "\n";
//------------------------------------------------------------------

In other words, we would have a reverseRange() function that returns a
wrapper object that has reverse iterators for its begin() and end()
functions.

Other applications would be to traverse only part of the range, such as:

for(int element: subrange(table, 0, 3)) std::cout << " " << element;

I haven't found any utility wrappers for this in the new standard, so
I suppose the only way is to write such wrappers oneself.

So my question is: What would be the simplest implementation for eg. the
'reverseRange()' function above?

This is the "simplest" implementation I could come up with:

//------------------------------------------------------------------
#include <iterator>

template<typename Cont_t>
struct RevRange
{
typename Cont_t::reverse_iterator b, e;
RevRange(Cont_t& c): b(c.rbegin()), e(c.rend()) {}
typename Cont_t::reverse_iterator begin() { return b; }
typename Cont_t::reverse_iterator end() { return e; }
};

template<typename Elem_t, std::size_t size>
struct RevRangeArray
{
std::reverse_iterator<Elem_t*> b, e;
RevRangeArray(Elem_t (&array)[size]): b(array+size), e(array) {}
std::reverse_iterator<Elem_t*> begin() { return b; }
std::reverse_iterator<Elem_t*> end() { return e; }
};

template<typename Container_t>
inline RevRange<Container_t> reverseRange(Container_t& c)
{ return RevRange<Container_t>(c); }

template<typename Elem_t, std::size_t size>
inline RevRangeArray<Elem_t, size> reverseRange(Elem_t (&array)[size])
{ return RevRangeArray<Elem_t, size>(array); }
//------------------------------------------------------------------

It's a bit complicated and verbose, and I was wondering if a simpler
solution could be possible (and also if this could be done with one
single class rather than having to use two).

Juha Nieminen

unread,
May 18, 2012, 2:17:46 PM5/18/12
to
Juha Nieminen <nos...@thanks.invalid> wrote:
> It's a bit complicated and verbose, and I was wondering if a simpler
> solution could be possible (and also if this could be done with one
> single class rather than having to use two).

This is slightly simpler:

//-------------------------------------------------------------------
#include <iterator>

template<typename Iter_t>
struct RangeWrapper
{
Iter_t mBegin, mEnd;
RangeWrapper(Iter_t b, Iter_t e): mBegin(b), mEnd(e) {}
Iter_t begin() { return mBegin; }
Iter_t end() { return mEnd; }
};

template<typename Container_t>
RangeWrapper<typename Container_t::reverse_iterator>
revRange(Container_t& container)
{
return { container.rbegin(), container.rend() };
}

template<typename Elem_t, std::size_t size>
RangeWrapper<std::reverse_iterator<Elem_t*>>
revRange(Elem_t (&array)[size])
{
typedef std::reverse_iterator<Elem_t*> Iter_t;
return { Iter_t(array + size), Iter_t(array) };
}
//-------------------------------------------------------------------

woodb...@gmail.com

unread,
May 19, 2012, 1:30:19 AM5/19/12
to
On Friday, May 18, 2012 12:20:41 PM UTC-5, Juha Nieminen wrote:
> I was thinking: How hard would it be to use the range-based for syntax
> for ranges other than the full begin-end range. For instance, what if
> you wanted it to traverse the container backwards instead of forwards?
>
> What I mean is that one could write something like this:
>
> //------------------------------------------------------------------
> int table[] = { 1, 3, 5, 7, 9 };
> std::vector<int> v(table, std::end(table));
>
> std::cout << "Forwards:\n";
>
> for(int element: table) std::cout << " " << element;
> for(int element: v) std::cout << " " << element;
>
> std::cout << "\nBackwards:\n";
>
> for(int element: reverseRange(table)) std::cout << " " << element;
> for(int element: reverseRange(v)) std::cout << " " << element;
>
> std::cout << "\n";
> //------------------------------------------------------------------
>
> In other words, we would have a reverseRange() function that returns a
> wrapper object that has reverse iterators for its begin() and end()
> functions.
>
> Other applications would be to traverse only part of the range, such as:
>
> for(int element: subrange(table, 0, 3)) std::cout << " " << element;
>
> I haven't found any utility wrappers for this in the new standard, so
> I suppose the only way is to write such wrappers oneself.
>

I'm not sure about reversing, but for ranges it
might make sense to use a range class that has
begin and end function members. The following
is from the C++ Middleware Writer.


void
bigtest::Marshal (::cmw::SendBufferCompressed& buf
, boost::sub_range<std::vector<int32_t> > const& az1
)
{
::cmw::Counter cntr(msg_length_max);
cntr.Add(sizeof(int));
cntr.MultiplyAndAdd(boost::distance(az1), sizeof(int32_t));
buf.Receive32(boost::distance(az1));
for (auto const& it35 : az1) {
buf.Receive(&it35, sizeof(int32_t));
}
buf.Compress();
}


Shalom,
Brian
Ebenezer Enterprises
http://webEbenezer.net
0 new messages