2010-12-10 21 views
11

Bueno, sé por qué, es porque no hay una conversión, pero ¿por qué no hay una conversión? ¿Por qué los iteradores de reenvío pueden pasar a iteradores inversos, pero no al revés? Y más importante aún, ¿qué puedo hacer si quiero hacer esto? ¿Hay algún adaptador que te permita iterar hacia atrás usando un iterador directo?¿Por qué no puedo convertir un iterador inverso en un iterador directo?

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 
+14

Hay una conversión: 'backward.base();' – ybungalobill

+0

Estoy bastante seguro de que puedes usar 'reverse_iterator 'donde sea necesario pasando el tipo de iterador como argumento de plantilla donde quiera que use' iterator'. ¿No soluciona tu problema? – Grozz

+1

Tienes toda la razón ybungalobill; mi código real es un poco más complejo que este y probé la base(), pero me dio errores, así que me rendí y mi cerebro borró mi conocimiento de ello. ¡Gracias! Si agrega ese texto exacto como respuesta, lo aceptaré, ya que realmente * es * una respuesta. –

Respuesta

15

Puede escribir una función auxiliar. Una particularidad de reverse_iterator es que base() da un iterador directo que está próximo del valor al que se refiere el iterador inverso. This is because a reverse iterator physically points to the element after the one it logically points to. Entonces, para tener el iterador directo al mismo elemento que su reverse_iterator, necesitará decrementar el resultado de base() en uno, o puede incrementar el iterador inverso primero, luego tome el .base() de eso.

Ambos ejemplos se muestran a continuación:

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

Advertencia: este comportamiento es diferente de la de la reverse_iterator(iterator) constructor.

+0

Probablemente make_forward() debería estar especializado para punteros. – Abyx

+0

Parece que ybungalobill no quiere el representante, así que como la primera respuesta para mencionar base() gana :) ¡Gracias! –

+0

@Abyx: Sí, ya que no puede disminuir el puntero temporal devuelto por 'rit.base()', podría ser mejor crear primero una variable con nombre de 'tipo_elerador'. Sin embargo, no se necesita especialización. – visitor

0

Puede subir al ataque de iterador iterador inversa usando este código

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

_Why_. En una gran lista, usted está solicitando muchos cruces excesivos, y esto es mucho más complicado que simplemente '(reverseIter + 1) .base()' – bobobobo

+0

¿Qué lista? es un * vector *. – Abyx

+0

Si está utilizando iteradores (a diferencia de la simple indexación de enteros), supongo que la razón por la que está haciendo esto es poder aplicar esta fórmula a cualquier 'std :: container' que use iteradores. El recorrido de 'std :: list' es más caro que' std :: vector', por lo que es mucho mejor con el desplazamiento (solo 1 elemento). – bobobobo

1

Es muy común tener dos iteradores (inverso) abarcan una gama de valores (como en begin(),end() y rbegin(),rend()). Para cualquier rango descrito por los dos iteradores inversos rA,rB, el rango rB.base(),rA.base() abarcará el mismo rango en la dirección de avance.

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

Si conceptualmente sólo está interesado en un solo elemento (como el resultado de find_if), a continuación, utilizar make_forward por @visitor. Incluso en este caso, la idea rango ayuda a hacer un seguimiento de la validez del iterador inverso:

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