简体   繁体   中英

Reverse iterate over a std::vector with forward iterators

If I have a function which takes a std::vector<T>::const_iterator called begin and a std::vector<T>::const_iterator called end, is it possible for me to iterate over it in a backwards direction?

UPDATE

I can't change the function signature, which is like this:

void func(Foo::const_iterator begin, Foo::const_iterator end) 
{
   ...
}

and called with:

func(foo.begin(), foo.end());

which I also can't change

Yes, you can.

template <typename Foo>
void test(typename Foo::const_iterator begin,
          typename Foo::const_iterator end)
{
  std::reverse_iterator<typename Foo::const_iterator>
    rbegin(end),
    rend(begin);
  std::copy(rbegin, rend, std::ostream_iterator<typename std::iterator_traits<typename Foo::const_iterator>::value_type>(std::cout));
}

int main()
{
  std::vector<int> v{3,1,4,1,5,9,2,6};
  test<std::vector<int> >(v.begin(), v.end());
}

I may have misunderstood the question, but do you just need:

while (begin != end) {
    --end;
    // do something with *end
}

If you need an iterator that goes backwards, ipc's answer gives you one.

In practice with vector you could probably get away with while (begin != end--) , but don't be tempted. It's undefined behavior to decrement an iterator in the case where it's at the start of the vector (ie when it's equal to the result of vector::begin() ).

This code requires at least a BidirectionalIterator. Fortunately, vector has a RandomAccessIterator, which is even better.

If you genuinely only had a ForwardIterator, then you'd have to iterate over the range and store the iterator values somewhere (like a stack ), and then use them in reverse order:

std::stack<Foo::const_iterator> iterators;
while (begin != end) {
    iterators.push(begin);
    ++begin;
}
while (!iterators.empty()) {
    Foo::const_iterator i = iterators.top();
    // do something with *i
    iterators.pop();
}

This code requires at least a ForwardIterator (it will not work with a mere InputIterator).

Yes, you can use std::reverse_iterator . It is also a good idea not to specify the type of the iterator explicitly. Use a template argument instead.

#include <vector>
#include <algorithm>
#include <iostream>
#include <iterator>

template <typename BidirectionalIterator>
void x(BidirectionalIterator b, BidirectionalIterator e) {
  std::reverse_iterator<BidirectionalIterator> rb(e), re(b);
  std::for_each(rb, re, 
                [](typename BidirectionalIterator::reference x) 
                { std::cout << x << std::endl;});
}

int main()
{
  std::vector<int> v{1,2,3,4};
  x(begin(v), end(v));
  return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM