2010-01-25 19 views
5

Sto riscontrando un problema nell'utilizzo di iteratori inversi const su contenitori non-const con gcc. Bene, solo alcune versioni di gcc.operatori di confronto gt reverse_iterator mancanti?

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

Questo programma viene compilato OK e viene eseguito con gcc 4.2.1 (Mac Leopard) e con Visual Studio 8 e 9 (Windows), e con gcc 4.1.2 (Linux).

Tuttavia, c'è un errore di compilazione con gcc 3.4.4 (cygwin) e 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>]()' 

Si tratta di un bug nelle versioni precedenti di gcc?

A causa di altri problemi con gcc 4.2.1 su Mac, dobbiamo usare gcc 4.0.1 su Mac, quindi usare semplicemente il compilatore più recente non è una soluzione perfetta per me. Quindi suppongo di dover cambiare il modo in cui utilizzo gli iteratori inversi. Eventuali suggerimenti?

+0

Per una soluzione alternativa, '! (R == v.rend())' funziona? In alternativa puoi provare con la versione non inversa tramite 'r.base()'. –

+0

Più probabile un'omissione; Penso che il pieno supporto per l'intero STL sia * ancora * in corso, anche se molto vicino. Ai tempi di 3.4.4 era un po 'incompleto. – meagar

+0

@gf Bel tentativo, "! (R == v.rend())" non funziona. Entrambi gli operatori "! =" E "==" sono mancanti. –

risposta

10

È un difetto nello standard corrente: http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#280

Edit: Elaborando un bit: Il problema è che, nello standard corrente:

  • vector::reverse_iterator è specificato come std::reverse_iterator<vector::iterator>, e vector::const_reverse_iterator come std::reverse_iterator<vector::const_iterator>.
  • Gli operatori relazionali su std::reverse_iterator sono definiti con un singolo parametro di modello, rendendo reverse_iterator<iterator> e reverse_iterator<const_iterator> non confrontabili.

Nel codice, si confronta una const_reverse_iterator con il risultato della chiamata "rend()" a un vettore non-const, che è una (non-const) reverse_iterator.

In C++ 0x, due relative variazioni sono fatti per risolvere i problemi in questo modo:

  • operatori relazionali su reverse_iterator ora prendere due parametri di modello
  • contenitori come vettore avere metodi aggiuntivi per richiedere esplicitamente un const_iterator : cbegin(), cend(), crbegin() e crend ​​().

Nel suo caso, una soluzione potrebbe essere quella di richiedere esplicitamente la const_reverse_iterator per 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

Bella risposta. È più un bug nello standard che un bug in gcc. –

+0

@Christopher Bruns: Immagino che fare crend ​​non-const, come r, possa far funzionare le cose. –

+0

@Eric Malenfant: re il tuo punto elenco puntato: Penso che const_reverse_iterator sia definito come "reverse_iterator ", non solo "const_iterator" –

2

cose a caso vorrei provare:

Fusioni il ritorno da rend() per un const_reverse_iterator per vedere se il problema è in confronto di un regolare per un iteratore const:

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

Se che doesn' t lavoro, che ne dici di cambiare r da un const_reverse_iterator a un normale iteratore inverso.

Nessun indizio se questi funzionano, ma è quello che proverei in questa situazione.

+0

Questo cast risolve il problema. Non è molto carina ma funziona. –

1

potrebbe essere un bug nella vecchia versione di gcc, ma la mia ipotesi è che il bug sia nel codice: non è stato possibile effettuare l'operazione #include <iterator>. Probabilmente vale la pena guardare oltre se il fixing non risolve il problema.

D'altra parte, se si sta utilizzando il reverse_iterator come indicato (cioè il corpo del ciclo è cout << *r;) si dovrebbe probabilmente basta usare 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); 

C'è anche un copy_backwards, ma io non credere che farà quello che vuoi

Edit: Un'altra possibilità da considerare: se l'aggiunta l'intestazione richiesta non funziona, e si ha realmente bisogno l'iteratore inverso, si potrebbe considerare l'utilizzo di STLPort al posto della libreria nativa (almeno per i compilatori più vecchi).

+1

L'aggiunta di "#include " non modifica il comportamento. –

2

Poiché gli iteratori devono essere dello stesso tipo essere comparabili, e un contenitore non const produce iteratori non costanti, perché non dichiarare e inizializzare l'iteratore finale allo stesso tempo.

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

Con un compilatore più vecchio questo potrebbe anche dare un piccolo vantaggio in termini di prestazioni.

Problemi correlati