2013-06-10 26 views
13

Ho una funzione che assomiglia a questo:Come scrivere un ciclo for che utilizza sia un iteratore sia un contatore di indici?

void myclass::myfunc() 
{ 
    int i; 
    for(std::vector<Foo>::iterator it = var.begin(), i = 0; it < var.end(); it++, i++) 
    { 
     /* ... */ 
    } 
} 

sto ottenendo questo errore:

Cannot convert from int to std::_Vector_iterator<>

Cosa c'è di sbagliato con questo codice?

+2

Usa ' ++ it' per incrementare iteratore, perché 'it ++' è il post-incremento e impiega tempo inutile. – marbel82

risposta

11

Si può fare in questo modo:

int i = 0; 
for(std::vector<int>::iterator it = v.begin(); it < v.end(); ++it, ++i){} 
+0

Contrassegnare questo come una risposta perché è il primo. Grazie. – Igor

+2

perché l'inconsistenza di 'it ++' e '++ i'? – TemplateRex

+7

In realtà, sarebbe preferibile utilizzare solo il pre-incremento; mentre importa poco per 'i', potrebbe essere importante per' it' a seconda di come * grasso * è l'iteratore. –

3

Sbarazzarsi della parte i=0; (almeno all'interno dell'intestazione del loop).

Inoltre, se ti ostini a fare questo a tutti, è possibile utilizzare:

for (auto it : var) 

o:

for (auto it = var.begin(); it != var.end(); ++it) 

... invece. Poiché stai utilizzando un iteratore di accesso casuale, ciò che hai come i equivale a it - var.begin(). Al contrario, si potrebbe utilizzare:

for (int i=0; i<var.size(); i++) 

... e ottenere un iteratore quando necessario come var.begin() + i.

A seconda di cosa si trova nel corpo del loop, probabilmente si desidera eliminare completamente il ciclo e sostituirlo con un algoritmo.

+0

Mi piacerebbe usare "auto", ma temo che non sia compatibile con OS X 10.6 XCode. Inoltre sto usando gli iteratori per l'efficienza, altrimenti userò sicuramente solo il tuo 3 ° modulo. Inoltre cosa intendi con "sbarazzarsi del loop". Potresti chiarire come vado attraverso il vettore? – Igor

18

Il problema è con questa parte del ciclo for:

std::vector<Foo>::iterator it = var.begin(), i = 0 

C++ è interpretare questo non con due prospetti separati da virgola, ma come una dichiarazione variabile per una variabile denominata it che è un iteratore, e come una nuova dichiarazione di una variabile i è un iteratore e inizializzata su 0. L'errore è dovuto al fatto che non è possibile inizializzare un iteratore vector su 0.

Per risolvere questo problema, è necessario issare la definizione all'esterno del ciclo :

int i = 0; 
std::vector<Foo>::iterator it = var.begin(); 
for(; it < var.end(); it++, i++) 
{ 
    // ... 
} 

Oppure spostare l'inizializzazione del i fuori del ciclo:

int i = 0; 
for(std::vector<Foo>::iterator it = var.begin(); it < var.end(); it++, i++) 
{ 
    // ... 
} 

C'è un ultima opzione, però. Se è necessario tenere traccia dell'indice nel vettore che si sta esaminando, è possibile considerare solo l'utilizzo di un ciclo di conteggio (senza l'iteratore), o semplicemente l'iteratore e l'uso della sottrazione iteratrice per recuperare l'indice:

for (auto it = var.begin(); it != var.end(); ++it) { 
    // current position is it - var.begin(); 
} 

Spero che questo aiuti!

+0

Ho pensato che dal momento che ho già inizializzato l'iteratore sarà l'inizializzazione della variabile. Credo di aver sbagliato. Userò la correzione n. 2. Grazie. – Igor

-1

è necessario leggere sul operatore virgola.

La domanda How does the Comma Operator work ti darà alcune informazioni sul comportamento che stai ottenendo.

+4

Questo è sbagliato. Non c'è operatore virgola al lavoro qui, agisce solo come separatore. –

+0

Vedere questo bit del codice 'std :: vector :: iterator it = var.begin(), i = 0' - Kinda contiene una virgola! –

+0

Citazione da [Wikipedia] (http://en.wikipedia.org/wiki/Comma_operator): 'L'uso del token virgola come operatore è distinto dal suo uso in chiamate di funzioni e definizioni, ** dichiarazioni variabili **, dichiarazioni enum e costrutti simili, in cui funge da separatore. Può aiutare? –

1

Doppia iterazione:

using std::begin; using std::end; 
for (auto p = std::make_pair(begin(var), 0); p.first != end(var); ++p.first, ++p.second) { 
    /* ... */ 
} 

doppia iterazione con gli indici di nome/iteratori:

using std::begin; using std::end; 
int i; 
std::vector<Foo>::iterator it; 
for (std::tie(it, i) = std::make_pair(begin(var), 0); it != end(var); ++it, ++i) { 
    /* ... */ 
} 

o legare la coppia di cui sopra ad ogni iterazione alle variabili meglio denominate:

using std::begin; using std::end; 
for (auto p = std::make_pair(begin(var), 0); p.first != end(var); ++p.first, ++p.second) { 
    auto const& it = p.first; 
    int i = p.second; 
} 
Problemi correlati