2013-10-25 5 views
5

Ich habe einen Block in meinem Code, in dem die for-Schleife abhängig von einer Bedingung vorwärts oder rückwärts laufen sollte.Was ist der beste Weg, um die Richtung einer for-Schleife bedingt zu steuern

if (forwards) { 
    for (unsigned x = 0; x < something.size(); x++) { 
     // Lots of code 
    } 

} else { 
    for (unsigned x = something.size()-1 ; x >= 0 ; x--) { 
     // Lots of code 
    } 
} 

Gibt es eine gute Möglichkeit, dies einzurichten, also wiederhole ich nicht den gesamten Code innerhalb der for-Schleife zweimal?

Das 'etwas' in Frage ist ein std :: vector <>, also ist es vielleicht mit einem Iterator möglich? (Ich verwende C++ nicht 11)

+1

umgekehrter Iterator. – yngccc

+0

Verwenden Sie while oder do-while-Schleife –

+0

Beachten Sie, dass in der zweiten for-Schleife 'x> = 0 'immer wahr ausgewertet wird, da x unsigned ist. – doug

Antwort

6

Separate den Schleifenwert aus dem Wert, den Sie in der Schleife verwenden:

for (unsigned x2 = 0; x2 < something.size(); x2++) { 
    const int x = forward ? x2 : (something.size()-1) - x2; 
    // Lots of code using x 
} 
+0

Ich wählte dies als die Antwort als a) Ich benutzte es und b) es löste am meisten direkt die Frage, die ich stellte. Ich mag auch die anderen Antworten. Viele Möglichkeiten, eine Katze zu häuten! – joeButler

+0

Sie haben die Bedingung von außerhalb der Schleife nach innen verschoben - funktional, aber sicher nicht optimal, wenn dies ein leistungskritischer Code ist. Auf der anderen Seite, da Sie "viel Code" sagen, ist es unwahrscheinlich, dass die Bedingung eine erhebliche Belastung hinzufügen wird ... und Verzweigungsprognose wird zu Ihren Gunsten arbeiten. –

+0

Ja, ich stimme dem zu. Aber ich denke, es wird immer entweder eine bedingte Auswertung oder einen Funktionsaufruf geben. In meinem "echten" Code gibt es eine innere Schleife, die das schwere Heben durchführt, so wäre ich glücklich gewesen, mit einer der beiden Routen zu gehen, die die meiste Zeit dort verbracht wird. – joeButler

6

x Wahrscheinlich ist der einfachste Weg Lots of code auf eine Funktion mit dem Argument zu konvertieren und ersetzen Sie beiden Schleifenkörper mit einem Aufruf dieser Funktion:

void do_lots_of_stuff(unsigned x) { 
    // Lots of code 
} 

//////// 

if (forwards) { 
    for (unsigned x = 0; x < something.size(); x++) { 
    do_lots_of_stuff(x); 
    } 
} else { 
    for (unsigned x = something.size()-1 ; x >= 0 ; x--) { 
    do_lots_of_stuff(x); 
    } 
} 
+0

Bitte beheben Sie dies: 'für (unsigned x = something.size() - 1; x> = 0; x--) {' wie es eine Endlosschleife laufen wird. S/B 'für (int x = etwas.size() - 1; x> = 0; x--) {' – doug

2
template<typename Cont, typename Func> 
Func directional_for_each(Cont c, bool forwards, Func f) { 
    return forwards ? for_each(begin(c), end(c), f) : for_each(rbegin(c), rend(c), f); 
} 

wie folgt verwendet:

Da Sie nicht C++ 11 verwenden, müsste das Lambda mit 'Viele Codes mit x' durch eine an anderer Stelle definierte Funktion ersetzt werden.

3

Oder Sie können so etwas tun:

for (unsigned x = (forward ? 0: something.size()); x != (forward ? something.size() :0); forward? x++: x--) { 
    // Lots of code 
} 

Der Compiler wird es höchstwahrscheinlich optimieren und bewerten forward nur einmal, da es Wert ist nicht in der for Schleife ändern Ich gehe davon aus.

0

Ich bin gerade zufällig auf diese Frage gestoßen und dachte, ich könnte eine Lösung anbieten, ohne jede Schleife zu überprüfen, ob ich vorwärts oder rückwärts gehen soll.

// Could do 0xFFFFFFFFU if unsigned is 32bits. 
const unsigned MAX_UINT = 0U - 1U; 

// Will need this later. 
const bool backwards = !forwards; 

// temp is either going to be one or zero. 
const unsigned temp = unsigned(forwards); 

// By adding it to all ones, if temp is ones the mask is all zeros 
// else if temp is zero we get all ones. 
const unsigned mask = temp + MAX_UINT; 

// Bit shift temp over such that it will push all of the ones after 
// the first bit to all zeros if temp is one. This means we will 
// either have a one or a negative one if temp is zero. 
const int delta = int((temp << 1) + MAX_UINT); 

const int size = something.size(); 

// The mask will be zero if forwards is true therein i will start out 
// at zero else the mask will be all ones therein return (size - 1). 
for(int i = int((size - 1) & mask); 
// This may be a more complicated check, but there is only one conditional branch. 
    (forwards && (i < size)) || (backwards (0 <= i)); 
    i += delta) 
{ 
    // Lots of code 
} 
Verwandte Themen