Почему я не могу преобразовать обратный итератор в форвардный итератор?
Ну, я знаю, почему, потому что нет конверсии, но почему нет конверсии? Почему переадресация итераторов может быть повернута на обратные итераторы, но не наоборот? И что еще более важно, что я могу сделать, если я хочу это сделать? Есть ли какой-либо адаптер, который позволяет вам итератировать назад с помощью передового итератора?
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);