2013-10-25 18 views
5

Mam blok w moim kodzie, w którym pętla for powinna działać w przód lub w tył w zależności od warunku.Jaki jest najlepszy sposób warunkowo kontrolować kierunek pętli for

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

Czy istnieje dobry sposób na ustawienie tego, więc nie powtórzę całego kodu w pętli for dwa razy?

"Coś", o które chodzi, to std :: vector <>, więc może jest to możliwe z iteratorem? (nie używam C++ 11)

+1

odwrotny iterator. – yngccc

+0

Użyj pętli while lub do-while –

+0

Należy pamiętać, że w drugiej pętli 'x> = 0 'zawsze będzie sprawdzać true, ponieważ x jest unsigned. – doug

Odpowiedz

6

wyodrębnienia wartości pętli od wartości używanego wewnątrz pętli:

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

Wybrałem to jako odpowiedź jako a) Użyłem go i b) najbardziej bezpośrednio rozwiązałem postawione przeze mnie pytanie. Też lubię inne odpowiedzi. Wiele sposobów na skórze kota! – joeButler

+0

Przesunąłeś warunkowy z poza pętli do środka - funkcjonalny, ale na pewno nie optymalny, jeśli jest to kod krytyczny pod względem wydajności. Z drugiej strony, ponieważ mówisz "dużo kodu", jest mało prawdopodobne, że warunkowe doda znacznego obciążenia ... a prognozy rozgałęzień będą działać na twoją korzyść. –

+0

Tak, zgadzam się z tym. Ale myślę, że zawsze będzie albo warunkowy do oceny, albo wywołanie funkcji. W moim "prawdziwym" kodzie jest wewnętrzna pętla, która robi ciężki lifting, więc byłbym szczęśliwy, gdyby jechałem z którąkolwiek trasą, w której spędza się ogromną większość czasu. – joeButler

6

Prawdopodobnie Najprostszym sposobem jest przekształcenie Lots of code do funkcji z argumentem x i wymienić oba ciała pętli przy wywołaniu tej funkcji:

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

Napraw to: 'dla (unsigned x = something.size() - 1; x> = 0; x--) {' ponieważ spowoduje uruchomienie nieskończonej pętli. S/B 'for (int x = something.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); 
} 

Używany tak:

Ponieważ nie używasz C++ 11, lambda zawierająca "Partie kodu z użyciem x" musiała zostać zastąpiona przez funkcję zdefiniowaną gdzie indziej.

3

Albo można zrobić coś takiego:

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

Kompilator najprawdopodobniej zoptymalizować go i oceny forward tylko raz, ponieważ jest to wartość nie zmienia się w pętli for zakładam.

0

Po prostu zdarzyło mi się natknąć na to pytanie i pomyślałem, że mogę zapewnić rozwiązanie bez warunkowego sprawdzania każdej pętli, czy iść do przodu czy do tyłu.

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