2010-01-25 11 views
5

Tengo un problema al usar iteradores inversos const en contenedores no const con gcc. Bueno, solo ciertas versiones de gcc.gcc reverse_iterator operadores de comparación faltantes?

#include <vector> 
#include <iostream> 

using namespace std; 

int main() { 
    const char v0[4] = "abc"; 
    vector<char> v(v0, v0 + 3); 

    // This block works fine 
    vector<char>::const_iterator i; 
    for (i = v.begin(); i != v.end(); ++i) 
     cout << *i; 
    cout << endl; 

    // This block generates compile error with gcc 3.4.4 and gcc 4.0.1 
    vector<char>::const_reverse_iterator r; 
    for (r = v.rbegin(); r != v.rend(); ++r) 
     cout << *r; 
    cout << endl; 

    return 0; 
} 

Este programa se compila y se ejecuta bien con gcc 4.2.1 (Mac Leopard) y con Visual Studio 8 y 9 (Windows) y con gcc 4.1.2 (Linux).

Sin embargo, hay un error de compilación con gcc 3.4.4 (cygwin) y con gcc 4.0.1 (Mac Snow Leopard).

test.cpp:18: error: no match for 'operator!=' in 'r != std::vector<_Tp, _Alloc>::rend() [with _Tp = char, _Alloc = std::allocator<char>]()' 

¿Esto es un error en las versiones anteriores de gcc?

Debido a otros problemas con gcc 4.2.1 en Mac, necesitamos usar gcc 4.0.1 en Mac, así que simplemente usar el compilador más nuevo no es la solución perfecta para mí. Así que supongo que necesito cambiar la forma en que uso los iteradores inversos. ¿Alguna sugerencia?

+0

Para una solución alternativa, ¿funcionaría '! (R == v.rend())'? Alternativamente, puede intentarlo con la versión no inversa a través de 'r.base()'. –

+0

Es más probable que sea una omisión; Creo que el soporte completo para todo el STL * está * en curso, aunque muy cerca. En los días de 3.4.4 estaba algo incompleto. – meagar

+0

@gf Buen intento, "! (R == v.rend())" no funciona. Ambos operadores "! =" Y "==" faltan. –

Respuesta

10

que es un defecto en la norma actual: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#280

Editar: Elaborando un poco: La cuestión es que, en la norma actual:

  • vector::reverse_iterator se especifica como std::reverse_iterator<vector::iterator>, y vector::const_reverse_iterator como std::reverse_iterator<vector::const_iterator>.
  • Los operadores relacionales en std::reverse_iterator se definen con un solo parámetro de plantilla, por lo que reverse_iterator<iterator> y reverse_iterator<const_iterator> no son comparables.

En su código, se compara un const_reverse_iterator con el resultado de la llamada "rend()" en un vector no constante, que es una (no constante) reverse_iterator.

En C++ 0x, se hacen dos cambios relacionados a solucionar problemas como éste:

  • operadores relacionales en reverse_iterator ahora toman dos parámetros de plantilla
  • Contenedores como vector de tener métodos adicionales para solicitar explícitamente una const_iterator : cbegin(), cend(), crbegin() y crend ​​().

En su caso, una solución alternativa sería solicitar explícitamente la const_reverse_iterator para rend():

vector<char>::const_reverse_iterator r; 
const vector<char>::const_reverse_iterator crend = v.rend(); 
for (r = v.rbegin(); r != crend; ++r) 
    cout << *r; 
+0

Buena respuesta. Es más un error en el estándar que un error en gcc. –

+0

@Christopher Bruns: Creo que hacer crend ​​no const, como r, haría que las cosas funcionen. –

+0

@Eric Malenfant: vuelva a su primer punto: Creo que const_reverse_iterator se define como "reverse_iterator ", no solo "const_iterator" –

2

cosas al azar que iba a probar:

emitir el regreso de rend() a un const_reverse_iterator para ver si el problema se encuentra en la comparación de un periódico a un iterador const:

r != static_cast<vector<char>::const_reverse_iterator>(v.rend()) 

Si Eso no t trabajo, ¿qué le parece cambiar r de un const_reverse_iterator a un iterador inverso normal?

No tengo idea si funcionan, pero eso es lo que probaría en esta situación.

+0

Ese yeso soluciona el problema. No es muy bonito, pero funciona. –

1

podría ser ser un error en la vieja versión de gcc, pero mi suposición es que el error está en tu código - no has podido #include <iterator>. Probablemente solo valga la pena buscar más si corregir eso no soluciona el problema.

Por otro lado, si usted está utilizando el reverse_iterator como se muestra (es decir, el cuerpo del bucle es cout << *r;) se debe, probablemente, sólo tiene que utilizar std::copy:

std::ostream_iterator<char> output(std::cout); 

// frontwards 
std::copy(v.begin(), v.end(), output); 

// backwards 
std::copy(v.rbegin(), v.rend(), output); 

También hay un copy_backwards, pero no creas que hará lo que quieras.

Editar: Otra posibilidad a considerar: si agregar el encabezado requerido no funciona, y realmente necesita el iterador inverso, puede considerar usar STLPort en lugar de la biblioteca nativa (al menos para los compiladores anteriores).

+1

Agregar "#include " no cambia el comportamiento. –

2

Desde los iteradores necesitan ser del mismo tipo para ser comparables, y un recipiente no const produce iteradores no const, por qué no declarar e inicializar el iterador final al mismo tiempo.

for (vector<char>::const_reverse_iterator r = v.rbegin(), end_it = v.rend(); r != end_it; ++r) 
    cout << *r; 

Con un compilador anterior, esto incluso podría ofrecer un pequeño beneficio de rendimiento.

Cuestiones relacionadas