¿Hay un adaptador de contenedor que invierta la dirección de los iteradores para que pueda iterar sobre un contenedor en reversa con un bucle for basado en rango?
Con iteradores explícitos convertiría esto:
for (auto i = c.begin(); i != c.end(); ++i) { ...
dentro de esto:
for (auto i = c.rbegin(); i != c.rend(); ++i) { ...
Quiero convertir esto:
for (auto& i: c) { ...
a esto:
for (auto& i: std::magic_reverse_adapter(c)) { ...
¿Existe tal cosa o tengo que escribirla yo mismo?
c++
c++11
ranged-loops
Alex B
fuente
fuente

beginhaciaend, o para tratar con iteradores de flujo y similares. Los algoritmos de rango serían geniales, pero en realidad son solo azúcar sintáctica (a excepción de la posibilidad de una evaluación diferida) sobre los algoritmos iteradores.template<typename T> class reverse_adapter { public: reverse_adapter(T& c) : c(c) { } typename T::reverse_iterator begin() { return c.rbegin(); } typename T::reverse_iterator end() { return c.rend(); } private: T& c; };Se puede mejorar (agregarconstversiones, etc.) pero funciona:vector<int> v {1, 2, 3}; reverse_adapter<decltype(v)> ra; for (auto& i : ra) cout << i;impresiones321template<typename T> reverse_adapter<T> reverse_adapt_container(T &c) {return reverse_adapter<T>(c);}entonces puedes usarfor(auto &i: reverse_adapt_container(v)) cout << i;para iterar.parallel_forsería, con una condición aún más fuerte de "No me importa qué orden", si se incorporara al estándar de alguna forma. Por supuesto, también podría tener un azúcar sintáctico basado en rango :-)Respuestas:
En realidad Boost tiene como adaptador:
boost::adaptors::reverse.fuente
En realidad, en C ++ 14 se puede hacer con muy pocas líneas de código.
Esta es una idea muy similar a la solución de @ Paul. Debido a las cosas que faltan en C ++ 11, esa solución está un poco innecesariamente hinchada (además de definirse en olores estándar). Gracias a C ++ 14 podemos hacerlo mucho más legible.
La observación clave es que los bucles for basados en rango funcionan confiando en
begin()yend()para adquirir los iteradores del rango. Gracias a ADL , uno ni siquiera necesita definir su costumbrebegin()yend()en el espacio de nombres std ::.Aquí hay una solución de muestra muy simple:
Esto funciona como un encanto, por ejemplo:
imprime como se esperaba
NOTA
std::rbegin(),std::rend()ystd::make_reverse_iterator()aún no se implementan en GCC-4.9. Escribo estos ejemplos de acuerdo con el estándar, pero no se compilan en g ++ estable. Sin embargo, agregar stubs temporales para estas tres funciones es muy fácil. Aquí hay una implementación de muestra, definitivamente no completa pero funciona lo suficientemente bien para la mayoría de los casos:fuente
forward<T>en tureverseimplementación.using namespace stden un encabezado, lo cual no es una buena idea. ¿O me estoy perdiendo algo?Esto debería funcionar en C ++ 11 sin impulso:
fuente
stdespacio de nombres tiene un comportamiento indefinido según 17.6.4.2.1.make_reverse_iteratorno está en elstdespacio de nombres, por lo que no chocará con la versión de C ++ 14.Esto funciona para tí:
fuente
p.ej:
fuente
Si puede usar el rango v3 , puede usar el adaptador de rango inverso
ranges::view::reverseque le permite ver el contenedor al revés.Un ejemplo de trabajo mínimo:
Ver DEMO 1 .
Nota: Según Eric Niebler , esta función estará disponible en C ++ 20 . Esto se puede usar con el
<experimental/ranges/range>encabezado. Entonces lafordeclaración se verá así:Ver DEMO 2
fuente
ranges::viewha cambiado el nombre del espacio de nombresranges::views. Entonces, useranges::views::reverse.Si no usa C ++ 14, entonces encuentro a continuación la solución más simple.
Demostración .
No funciona para los contenedores / tipos de datos (como la matriz), que no tiene
begin/rbegin, end/rendfunciones.fuente
Simplemente podría usar el
BOOST_REVERSE_FOREACHque itera hacia atrás. Por ejemplo, el códigogenera el siguiente resultado:
fuente