40 Stimmen

Unterbrechung in std::for_each-Schleife

Wie kann ich bei der Verwendung des std::for_each-Algorithmus unterbrechen, wenn eine bestimmte Bedingung erfüllt ist?

33voto

Anton Belov Punkte 514

Sie können std::any_of (oder std::all_of oder std::none_of) z.B. wie folgt verwenden:

std::vector<int> a;
// ...     
std::all_of(a.begin(), a.end(), [&](int val) { 
  // return false if you want to break, true otherwise
  });

Dies ist jedoch eine verschwenderische Lösung (Rückgabewerte werden nicht wirklich für irgendetwas verwendet), und Sie sind besser dran, wenn Sie Ihre eigene Schleife schreiben.

18voto

Cătălin Pitiș Punkte 13785

Sie können verwenden std::find_if Algorithmus, der anhält und den Iterator zum ersten Element zurückführt, auf das die Prädikatsbedingung angewendet wird true . Ihr Prädikat sollte also so geändert werden, dass es einen Booleschen Wert als Fortsetzungs- bzw. Unterbrechungsbedingung zurückgibt.

Dies ist jedoch ein Hack, so dass Sie die Algorithmen verwenden können.

Eine andere Möglichkeit ist die Verwendung von BOOST_FOREACH.

16voto

John Dibling Punkte 96619

Sie können die for_each() abbrechen, indem Sie eine Ausnahme von Ihrem Funktor auslösen. Dies ist jedoch oft keine gute Idee, und es gibt Alternativen.

Sie können den Zustand in Ihrem Funktor beibehalten. Wenn Sie die "Break"-Bedingung erkennen, setzen Sie einfach ein Flag in Ihrem Funktor und kehren dann bei jeder nachfolgenden Iteration einfach zurück, ohne die Aufgabe Ihres Funktors zu erfüllen. Natürlich wird dadurch die Iteration nicht gestoppt, was bei großen Sammlungen teuer sein kann, aber zumindest wird die Arbeit nicht mehr ausgeführt.

Wenn Ihre Sammlung sortiert ist, können Sie mit find() das Element finden, an dem Sie abbrechen wollen, und dann for_each von begin() bis zu dem von find() zurückgegebenen Element ausführen.

Schließlich können Sie eine for_each_if() . Auch hier wird die Iteration nicht gestoppt, aber der Funktor, der die Arbeit verrichtet, wird nicht ausgewertet, wenn das Prädikat als falsch ausgewertet wird. Hier sind 2 Varianten von for_each_xxx() einen, der einen Wert annimmt und die Arbeit ausführt, wenn operator==() zu true ausgewertet wird, und einen anderen, der zwei Funktoren annimmt; einen, der einen Vergleich ala find_if() durchführt, und den anderen, der die Arbeit ausführt, wenn der Vergleichsoperator zu true ausgewertet wird.

/* ---

    For each
    25.1.1

        template< class InputIterator, class Function, class T>
            Function for_each_equal(InputIterator first, InputIterator last, const T& value, Function f)

        template< class InputIterator, class Function, class Predicate >
            Function for_each_if(InputIterator first, InputIterator last, Predicate pred, Function f)

    Requires:   

        T is of type EqualityComparable (20.1.1) 

    Effects:    

         Applies f to each dereferenced iterator i in the range [first, last) where one of the following conditions hold:

            1:  *i == value
            2:  pred(*i) != false

    Returns:    

        f

    Complexity: 

        At most last - first applications of f

    --- */

    template< class InputIterator, class Function, class Predicate >
    Function for_each_if(InputIterator first, 
                         InputIterator last, 
                         Predicate pred, 
                         Function f)
    {
        for( ; first != last; ++first)
        {
            if( pred(*first) )
                f(*first);
        }
        return f;
    };

    template< class InputIterator, class Function, class T>
    Function for_each_equal(InputIterator first, 
                            InputIterator last, 
                            const T& value, 
                            Function f)
    {
        for( ; first != last; ++first)
        {
            if( *first == value )
                f(*first);
        }
        return f;
    };

8voto

bayda Punkte 12869

Wenn Sie einige Aktionen durchführen möchten, während die Bedingung nicht erfüllt ist, müssen Sie vielleicht den Algorithmus auf etwas wie std::find_if ?

7voto

lothar Punkte 19157

Wie bereits von anderen gezeigt wurde, ist dies nur mit Workarounds möglich, die IMHO den Code verschleiern.

Ich schlage daher vor, die for_each-Schleife in eine reguläre for-Schleife umzuwandeln. Dadurch wird es für andere besser sichtbar, dass Sie break (und vielleicht sogar continue) verwenden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X