¿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
begin
haciaend
, 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 (agregarconst
versiones, etc.) pero funciona:vector<int> v {1, 2, 3}; reverse_adapter<decltype(v)> ra; for (auto& i : ra) cout << i;
impresiones321
template<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_for
serí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 tureverse
implementación.using namespace std
en un encabezado, lo cual no es una buena idea. ¿O me estoy perdiendo algo?Esto debería funcionar en C ++ 11 sin impulso:
fuente
std
espacio de nombres tiene un comportamiento indefinido según 17.6.4.2.1.make_reverse_iterator
no está en elstd
espacio 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::reverse
que 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 lafor
declaración se verá así:Ver DEMO 2
fuente
ranges::view
ha 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/rend
funciones.fuente
Simplemente podría usar el
BOOST_REVERSE_FOREACH
que itera hacia atrás. Por ejemplo, el códigogenera el siguiente resultado:
fuente