2017-01-23 2 views
0

Ich habe eine Funktion, die nach unten geschnitten, sieht aus wie:Rekursion ohne rebinding einen Verweis auf Iteration

// bar is basically a linked list with extra stuff tagged on 
void recurses(std::unique_ptr<bar> & P) 
{ 
    bool ok = decide_if_this_P_is_acceptable(P); 
    if (!ok) 
    { 
    recurses(P->getNextPtr()); 
    return; 
    } 
    // Now do lots more stuff involving the reference P and P.reset() 
} 

Die Bar Klasse eine Methode getNextPtr(), die ein std::unique_ptr<bar>& zurück, die dann wieder in rekursiv übergeben werden können genannt aussetzt.

Dies bläst leider den Stapel für einige große Eingänge. Ich möchte es in Iteration konvertieren, z.

void recurses(std::unique_ptr<bar> & P) 
{ 
    bar * N = nullptr; 
    for (;;) 
    { 
    bool ok = decide_if_this_P_is_acceptable(P); 
    if (ok) 
    { 
     break; 
    } 
    P = P->getNextPtr(); 
    } 
    // P is now OK 
    // Now do lots more stuff involving the reference P and P.reset() 
} 

Dies natürlich weigert zu kompilieren, weil wir nicht eine Referenz (std::unique_ptr<bar> & P) anbinden kann.

Wie kann ich die Rekursion verlieren, während der Rest der Funktion mutiert, welche Referenz auch immer als gut angesehen wurde?

+1

Warum nicht den rohen Zeiger von 'P' bekommen und damit zu arbeiten? –

+1

Ich bin nicht klar auf Ihre gewünschte Rückkehr Semantik. Ihre rekursive Version versucht, das Ergebnis des rekursiven Aufrufs zurückzugeben, der einen Basisfall ohne Rückgabewert hat, und der Funktionstyp ist ** void **. Sollte diese Rückmeldung nur ein Anruf ohne Auftrag sein? – Prune

+0

Was ist 'std :: unique_ptr :: getNextPtr'? – user2079303

Antwort

4

Die einfachste Lösung wäre std::reference_wrapper anstelle von rohen Referenz zu verwenden. Es ist rebindable:

void recurses(std::reference_wrapper<std::unique_ptr<bar>>& P) 
{ 
    bar * N = nullptr; 
    for (;;) 
    { 
    bool ok = decide_if_this_P_is_acceptable(P); 
    if (ok) 
    { 
     break; 
    } 
    P = P.get().getNextPtr(); 
    } 
    // P is now OK 
    // Now do lots more stuff involving the reference P and P.reset() 
} 

Beachten Sie die zusätzlichen .get() vor dem .getNextPtr() Anruf, der zunächst die zugrunde liegende Referenz zugreifen. Sie müssen das für alle Ihre Mitgliedsfunktionsaufrufe tun.

Alternativ können Sie nur einen Zeiger intern verwenden:

void recurses(std::unique_ptr<bar>& R) 
{ 
    std::unique_ptr<bar>* P = &R; 

    bar * N = nullptr; 
    for (;;) 
    { 
    bool ok = decide_if_this_P_is_acceptable(*P); 
    if (ok) 
    { 
     break; 
    } 
    P = &P->getNextPtr(); 
    } 
    // P is now OK 
    // Now do lots more stuff involving the reference P and P.reset() 
} 
+0

'while (! Decide_if_this_P_is_acceptable (* P))' ist ein mehr concise loop – Caleth

+0

unique_ptr * ist wahrscheinlich die offensichtliche Antwort, ich werde damit gehen. Vielen Dank –