2010-02-15 4 views
7

konstruieren Ich versuche, eine Doppelschleife über eine std :: list zu machen, um auf jedem Paar von Elementen zu arbeiten. Ich habe jedoch Probleme beim Initialisieren des zweiten Iterators. Der Code Ich mag würde schreiben ist:Wie man einen Iterator std :: list in Schleife mit Inkrement

for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    for(std::list<int>::iterator j = i+1; j != l.end(); ++j) { 
     ... 
    } 
} 

das nicht funktioniert, weil die Liste Iteratoren sind nicht zufällig-Zugriff, so dass Sie ein nicht tun. Aber ich habe Probleme, eine gute Alternative zu finden. der Compiler scheint nicht sehr glücklich mit std::list<int>::iterator j(i)++; zu sein, auf den ich einige Hoffnung hatte. Das zu erreichen, was ich will, scheint so zu sein, als müsste ich ein peinliches Extra-Inkrement haben, das nicht gut in die Struktur der for-Schleife passt.

Es gibt offensichtliche Alternativen (zum Beispiel mit einem Vektor!), Aber es scheint mir, dass es eine einigermaßen ordentliche Art und Weise geben sollte, dies zu tun, was ich gerade nicht sehe.

Vielen Dank im Voraus für jede Hilfe :)

Antwort

7

Wie wäre:

for (std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    for (std::list<int>::iterator j = i; ++j != l.end();) { 
     // ... 
    } 
} 
4
for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    std::list<int>::iterator j = i; ++j; 
    for(; j != l.end(); ++j) { 
     ... 
    } 
} 

Zurück im Spiel!

Eigentlich ist dies ein ziemlich allgemeines Idiom in numerischen Algorithmen, so dass ich es nicht als hässlich sehe.

9
for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    std::list<int>::iterator j = i; 
    for(std::advance(j, 1); j != l.end(); ++j) { 
     ... 
    } 
} 
+0

'advance' hat keinen Rückgabewert, es ändert das erste Argument. (Was ich persönlich nicht mag.) Das heißt, es ist einfach, eine "advance_copy" -Funktion zu schreiben. – GManNickG

+0

@GMan: Korrigiert. Ty! – dirkgently

+0

Kein Problem. Ich entschied mich für meine Idee als alternative Antwort. – GManNickG

2

Ich werde dran, nur die Idee, die ich in der Antwort dirkgently der hatte:

template <typename Iter, typename Dist> 
Iter advance_copy(Iter pIter, const Dist& pOffset) 
{ 
    std::advance(pIter, pOffset); 

    return pIter; 
} 

// ... 

typedef std::list<int> int_list; 

for(int_list::iterator i = l.begin(); i != l.end(); ++i) 
{ 
    for(int_list::iterator j = advance_copy(i, 1); j != l.end(); ++j) 
    { 
    } 
} 

Sie auch eine andere Klasse von Utility-Funktionen machen, zu helfen Machen Sie es kurz:

// for consistency, 
template <typename Iter> 
void increment(Iter& pIter) 
{ 
    ++pIter; 
} 

template <typename Iter> 
Iter increment_copy(Iter pIter) 
{ 
    return ++pIter; 
} 

// ... 

typedef std::list<int> int_list; 

for(int_list::iterator i = l.begin(); i != l.end(); ++i) 
{ 
    for(int_list::iterator j = increment_copy(i); j != l.end(); ++j) 
    { 
    } 
} 
1

Ich würde fo gehen r Sean Vorschlag, es sei denn es eine while-Schleife machen:

for (std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    std::list<int>::iterator j(i); 
    while(++j != l.end()) { 
     // ... 
    } 
} 
0

Wenn Sie bereits Boost, dann ist der einfachste Ansatz ist boost::next zu verwenden.

for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) 
    for(std::list<int>::iterator j = boost::next(i); j != l.end(); ++j) 
+0

Sie meinen Boost hat meine Idee gestohlen. :( – GManNickG

2

Die einfache „neat“ Alternative kann auf der Tatsache beruhen, dass die Liste mit Iterator überladene Operatoren ein Objekt von benutzerdefinierten Typ ist (im Gegensatz zu einem Typ in integrierten Gegensatz). (Natürlich ist dies nicht formal garantiert, aber man kann dies aufgrund der Art des Listencontainers erwarten.) Aus diesem Grund ist es möglich, den überladenen Präfixoperator ++ auf ein temporäres Objekt vom Listeniteratortyp anzuwenden.

Um das zu erreichen, was Sie wollen brauchen Sie nur eine temporäre Kopie von i zu erstellen, erhöht es das Präfix ++ und dann den resultierenden Wert verwenden j

for(std::list<int>::iterator i = l.begin(); i != l.end(); ++i) { 
    for(std::list<int>::iterator j = ++std::list<int>::iterator(i); j != l.end(); ++j) { 
    ... 
    } 
} 

Und das ist es zu initialisieren. Beachten Sie, dass dieser Trick ziemlich populär ist und von Zeit zu Zeit in echtem Code vorkommen kann. Beachten Sie auch, dass es im Allgemeinen nicht mit std::vector funktioniert, da viele Implementierungen normale integrierte Zeiger als Vektoriteratoren verwenden, aber normalerweise mit std::list arbeiten.

Allerdings persönlich würde ich das nicht wirklich in meinem Code verwenden.Sie haben bereits mehrere gute Antworten erhalten, indem Sie eine zusätzliche Codezeile hinzufügen.

Verwandte Themen