Using range-based for with alternative ranges

Discussion in 'C++' started by Juha Nieminen, May 18, 2012.

  1. 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, May 18, 2012
    #1
    1. Advertising

  2. Juha Nieminen <> 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) };
    }
    //-------------------------------------------------------------------
     
    Juha Nieminen, May 18, 2012
    #2
    1. Advertising

  3. Juha Nieminen

    Guest

    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
     
    , May 19, 2012
    #3
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    46
    Views:
    985
    Antoon Pardon
    Jul 25, 2006
  2. Lambda
    Replies:
    2
    Views:
    411
    James Kanze
    Jul 16, 2008
  3. Tomoyuki Kosimizu

    Range does not take an Range object.

    Tomoyuki Kosimizu, Nov 25, 2003, in forum: Ruby
    Replies:
    3
    Views:
    158
    Tomoyuki Kosimizu
    Nov 27, 2003
  4. Daniel Berger

    Bug in Range#end with exclusive ranges?

    Daniel Berger, Aug 10, 2004, in forum: Ruby
    Replies:
    4
    Views:
    107
    Gavin Sinclair
    Aug 12, 2004
  5. it_says_BALLS_on_your forehead

    extract range of lines using range op bug?

    it_says_BALLS_on_your forehead, Mar 3, 2006, in forum: Perl Misc
    Replies:
    3
    Views:
    197
    it_says_BALLS_on_your forehead
    Mar 3, 2006
Loading...

Share This Page