2013-06-10 6 views
13

Mam funkcję, która wygląda tak:Jak napisać pętlę for, która używa zarówno iteratora, jak i licznika indeksu?

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

Dostaję taki błąd:

Cannot convert from int to std::_Vector_iterator<>

Co jest nie tak z tym kodem?

+2

Zastosowanie ' ++, aby inkrementować iterator, ponieważ 'it ++' to post-inkrementacja i zajmuje niepotrzebny czas. – marbel82

Odpowiedz

11

Można to zrobić tak:

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

Oznaczanie jako odpowiedź, ponieważ jest to pierwsza. Dziękuję Ci. – Igor

+2

dlaczego niekonsekwencja 'it ++' i '++ i'? – TemplateRex

+7

Właściwie lepiej jest użyć tylko pre-increment; podczas gdy "i" ma niewielkie znaczenie, może to mieć znaczenie dla 'it' w zależności od tego, jak * gruby * jest iterator. –

3

Pozbądź się części i=0; (przynajmniej wewnątrz nagłówka pętli).

Ponadto, jeśli domagać się robi to w ogóle, należy rozważyć użycie:

for (auto it : var) 

czyli

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

... zamiast. Ponieważ i tak używasz Iteratora dostępu losowego, to co masz jako i jest równoważne it - var.begin(). Odwrotnie, można po prostu użyć:

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

... i dostać iterator gdy potrzebna jako var.begin() + i.

W zależności od tego, co znajduje się w ciele pętli, prawdopodobnie chcesz całkowicie pozbyć się pętli i zastąpić ją algorytmem.

+0

Chciałbym użyć "auto", ale obawiam się, że nie jest zgodny z OS X 10.6 XCode. Również używam iteratorów dla zwiększenia wydajności, w przeciwnym razie zdecydowanie użyłbym tylko trzeciego formularza. Co masz na myśli mówiąc "pozbyć się pętli"? Czy mógłbyś wyjaśnić, w jaki sposób przejść przez wektor? – Igor

18

Problem jest z tej części pętli for:

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

C++ interpretuje to nie jako dwa sprawozdania oddzielonych przecinkami, ale jako zmienna deklaracji zmiennej o nazwie it który jest iterator, a jako nowa deklaracja zmiennej i który jest iterator i inicjowany na 0. błąd jest, ponieważ nie można zainicjować vector iterator 0.

aby rozwiązać ten problem, trzeba podnosić definicję zewnątrz pętli :

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

Albo przenieść inicjalizacji i zewnątrz pętli:

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

Jest jedna ostatnia opcja, choć. Jeśli chcesz śledzić indeks w wektorze, który aktualnie przeglądasz, możesz rozważyć użycie pętli zliczania (bez iteratora) lub użycie tylko iteratora i użycie odejmowania iteratora do odzyskania indeksu:

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

Mam nadzieję, że to pomoże!

+0

Pomyślałem, że ponieważ już zainicjowałem iterator, będzie to inicjalizacja zmiennych. Chyba się myliłem. Będę używał poprawki nr 2. Dziękuję Ci. – Igor

-1

Musisz przeczytać na operatora przecinkami.

Pytanie How does the Comma Operator work zawiera informacje na temat zachowań, które otrzymujesz.

+4

To jest złe. W tym miejscu nie ma tu operatora przecinania, działa on tylko jako separator. –

+0

Zobacz ten fragment kodu 'std :: vector :: iterator it = var.begin(), i = 0' - Kinda ma przecinek! –

+0

Cytat z [Wikipedia] (http://en.wikipedia.org/wiki/Comma_operator): 'Używanie tokena przecinka jako operatora różni się od jego użycia w wywołaniach funkcji i definicjach, ** deklaracjach zmiennych **, deklaracje enum i podobne konstrukcje, gdzie działa jako separator. "Czy to pomaga? –

1

dwukrotnie iteracji:

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

podwójne iteracji nazwanych indeksów/iteratorami:

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) { 
    /* ... */ 
} 

lub wiążą wyżej pary w każdej iteracji lepiej wymienione zmiennych

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; 
} 
Powiązane problemy