开发者

Why can I not convert a reverse iterator to a forward iterator?

开发者 https://www.devze.com 2023-01-30 02:32 出处:网络
Well, I know why, it\'s because there isn\'t a conversion, but why isn\'t there a conversion? Why can forward iterators be turned to reverse iterators but not the other way round? And more importantly

Well, I know why, it's because there isn't a conversion, but why isn't there a conversion? Why can forward iterators be turned to reverse iterators but not the other way round? And more importantly, what can I do if I want to do this? Is there some adapter that allows you to iterate backwards using a forward iterator?

std::vector<int> buffer(10);
std::vector<int>::iterator forward = buffer.begin();
std::vector<int>::reverse_iterator backward = buffer.rbegin();
++forward;
++backward;
std::vector<int>::iterator forwardFromBackward = std::vector<int>::iterator(backward); // error! Can't convert from reverse_iterator to iterator!
std::vector<int>::reverse_iterator backwardFromForward = std::vector<int>::开发者_JAVA百科reverse_iterator(forward); // this is fine


You could write a helper function. One particularity of reverse_iterator is that base() gives a forward iterator that is next from the value that the reverse iterator dereferences to. This is because a reverse iterator physically points to the element after the one it logically points to. So to have the forward iterator to the same item as your reverse_iterator, you'll need to decrement the result of base() by one, or you could increment the reverse iterator first, then take the .base() of that.

Both examples are shown below:

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

//result is undefined if passed container.rend()
template <class ReverseIterator>
typename ReverseIterator::iterator_type make_forward(ReverseIterator rit)
{
    return --(rit.base()); // move result of .base() back by one.
    // alternatively
    // return (++rit).base() ;
    // or
    // return (rit+1).base().
}

int main()
{
    std::vector<int> vec(1, 1);
    std::vector<int>::reverse_iterator rit = vec.rbegin();
    std::vector<int>::iterator fit = make_forward(rit);
    std::cout << *fit << ' ' << *rit << '\n';
} 

Warning: this behavior is different from that of the reverse_iterator(iterator) constructor.


It's very common to have two (reverse) iterators span a range of values (such as in begin(),end() and rbegin(),rend()). For any range described by the two reverse iterators rA,rB, the range rB.base(),rA.base() will span the same range in the forward direction.

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

int main() {
  std::vector<int> vec{10,11,12,13,14,15};

  // spans the range from 13 to 10
  auto rfirst=std::rbegin(vec)+2;
  auto rlast=std::rend(vec);

  // Loops forward, prints 10 11 12 13
  for(auto it = rlast.base(); it != rfirst.base(); ++it){
    std::cout << *it << " ";
  }
}

If conceptually you are only interested in a single item (such as the result of find_if), then use make_forward by @visitor. Even in this case, the range idea helps to keep track of the validity of the reverse iterator:

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

int main() {
  std::vector<int> vec{10,11,12,13,14,15};

  auto rfirst=std::rbegin(vec);
  auto rlast=std::rend(vec);

  auto rfound = std::find_if(rfirst,rlast, [](int v){ return v<13; });

  if(rfound != rlast){
    std::cout << *rfound << " "; // prints 12
    auto forwardFound = make_forward(rfound) ; 
    std::cout << *forwardFound << " "; // prints 12
  }
}


You can get forward iterator from reverse iterator using this code

container.begin() + (reverseIter - container.rbegin() - 1);
0

精彩评论

暂无评论...
验证码 换一张
取 消