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

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

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

3 ответа

Решение

Вы могли бы написать вспомогательную функцию. Одна особенность 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) конструктор.

Очень часто два (обратных) итератора охватывают диапазон значений (например, в 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 @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
  }
}

Вы можете получить прямой итератор от обратного итератора, используя этот код

container.begin() + (reverseIter - container.rbegin() - 1);
Другие вопросы по тегам