Почему я не могу преобразовать обратный итератор в форвардный итератор?

Ну, я знаю, почему, потому что нет конверсии, но почему нет конверсии? Почему переадресация итераторов может быть повернута на обратные итераторы, но не наоборот? И что еще более важно, что я могу сделать, если я хочу это сделать? Есть ли какой-либо адаптер, который позволяет вам итератировать назад с помощью передового итератора?

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>::reverse_iterator(forward); // this is fine

Ответ 1

Вы можете написать вспомогательную функцию. Одна особенность reverse_iterator заключается в том, что base() дает форвардный итератор, следующий за значением, с которым обращаются обратные итераторы. Это потому, что обратный итератор физически указывает на элемент после того, как он логически указывает на. Поэтому, чтобы иметь передним итератором тот же элемент, что и ваш reverse_iterator, вам нужно уменьшить результат base() на один, или вы можете сначала увеличить обратный итератор, а затем взять .base() этого.

Оба примера показаны ниже:

#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';
} 

Предупреждение: это поведение отличается от поведения конструктора reverse_iterator(iterator).

Ответ 2

Очень часто бывает, что два (обратных) итератора охватывают диапазон значений (например, в begin(),end() и rbegin(),rend()). Для любого диапазона, описанного двумя обратными итераторами rA,rB, диапазон rB.base(),rA.base() будет охватывать тот же диапазон в прямом направлении.

#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 << " ";
  }
}

Если концептуально вас интересует только один элемент (например, результат find_if), используйте make_forward by @visitor. Даже в этом случае идея диапазона помогает отслеживать правильность обратного итератора:

#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
  }
}

Ответ 3

Вы можете получить итератор с обратным итератором с помощью этого кода

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