Namespaces
Variants

std::ranges::find_last, std::ranges::find_last_if, std::ranges::find_last_if_not

Von de.cppreference.net
 
 
Algorithmenbibliothek
Eingeschränkte Algorithmen und Algorithmen auf Bereichen (C++20)
Eingeschränkte Algorithmen, z. B. ranges::copy, ranges::sort, ...
Nicht modifizierende Sequenzoperationen    
Stapeloperationen
(C++17)
Suchoperationen
Modifizierende Sequenzoperationen
Kopieroperationen
(C++11)
(C++11)
Tauschoperationen
Transformationsoperationen
Generierungsoperationen
Entfernungsoperationen
Reihenfolgeändernde Operationen
(bis C++17)(C++11)
(C++20)(C++20)
Stichprobenoperationen
(C++17)

Sortier- und verwandte Operationen
Partitionierungsoperationen
(C++11)    

Sortieroperationen
Binäre Suchoperationen
(auf partitionierten Bereichen)
Mengenoperationen (auf sortierten Bereichen)
Mischoperationen (auf sortierten Bereichen)
Heap-Operationen
Minimum/Maximum-Operationen
(C++11)
(C++17)
Lexikografische Vergleichsoperationen
Permutationsoperationen


 
Eingeschränkte Algorithmen
Alle Namen in diesem Menü gehören zum Namensraum std::ranges
Nicht modifizierende Sequenzoperationen
Modifizierende Sequenzoperationen
Partitionierungsoperationen
Sortieroperationen
Binäre Suchoperationen (auf partitionierten Bereichen)
       
       
Mengenoperationen (auf sortierten Bereichen)
Heap-Operationen
Minimum/Maximum-Operationen
       
       
Permutationsoperationen
Faltungsoperationen
Numerische Operationen
(C++23)            
Operationen auf nicht initialisiertem Speicher
Rückgabetypen
 
Definiert in Header <algorithm>
Aufrufsignatur
template< std::forward_iterator I, std::sentinel_for<I> S,
          class T,
          class Proj = std::identity >
    requires std::indirect_binary_predicate
                 <ranges::equal_to, std::projected<I, Proj>, const T*>
constexpr ranges::subrange<I>
    find_last( I first, S last, const T& value, Proj proj = {} );
(1) (seit C++23)
(bis C++26)
template< std::forward_iterator I, std::sentinel_for<I> S,
          class Proj = std::identity,
          class T = std::projected_value_t<I, Proj> >
    requires std::indirect_binary_predicate
                 <ranges::equal_to, std::projected<I, Proj>, const T*>
constexpr ranges::subrange<I>
    find_last( I first, S last, const T& value, Proj proj = {} );
(seit C++26)
template< ranges::forward_range R,
          class T,
          class Proj = std::identity >
    requires std::indirect_binary_predicate
                 <ranges::equal_to,
                  std::projected<ranges::iterator_t<R>, Proj>, const T*>
constexpr ranges::borrowed_subrange_t<R>
    find_last( R&& r, const T& value, Proj proj = {} );
(2) (seit C++23)
(bis C++26)
template< ranges::forward_range R,
          class Proj = std::identity,
          class T = std::projected_value_t<ranges::iterator_t<R>, Proj> >
    requires std::indirect_binary_predicate
                 <ranges::equal_to,
                  std::projected<ranges::iterator_t<R>, Proj>, const T*>
constexpr ranges::borrowed_subrange_t<R>
    find_last( R&& r, const T& value, Proj proj = {} );
(seit C++26)
template< std::forward_iterator I, std::sentinel_for<I> S,
          class Proj = std::identity,
          std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
constexpr ranges::subrange<I>
    find_last_if( I first, S last, Pred pred, Proj proj = {} );
(3) (seit C++23)
template< ranges::forward_range R,
          class Proj = std::identity,
          std::indirect_unary_predicate
              <std::projected<ranges::iterator_t<R>, Proj>> Pred >
constexpr ranges::borrowed_subrange_t<R>
    find_last_if( R&& r, Pred pred, Proj proj = {} );
(4) (seit C++23)
template< std::forward_iterator I, std::sentinel_for<I> S,
          class Proj = std::identity,
          std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
constexpr ranges::subrange<I>
    find_last_if_not( I first, S last, Pred pred, Proj proj = {} );
(5) (seit C++23)
template< ranges::forward_range R,
          class Proj = std::identity,
          std::indirect_unary_predicate
              <std::projected<ranges::iterator_t<R>, Proj>> Pred >
constexpr ranges::borrowed_subrange_t<R>
    find_last_if_not( R&& r, Pred pred, Proj proj = {} );
(6) (seit C++23)
template< /*execution-policy*/ Ep,
          std::random_access_iterator I, std::sized_sentinel_for<I> S,
          class Proj = std::identity,
          class T = std::projected_value_t<I, Proj> >
    requires std::indirect_binary_predicate
                 <ranges::equal_to, std::projected<I, Proj>, const T*>
ranges::subrange<I> find_last( Ep&& policy, I first, S last,
                               const T& value, Proj proj = {} );
(7) (seit C++26)
template< /*execution-policy*/ Ep, /*sized-random-access-range*/ R,
          class Proj = std::identity,
          class T = std::projected_value_t<ranges::iterator_t<R>, Proj> >
    requires std::indirect_binary_predicate
                 <ranges::equal_to,
                  std::projected<ranges::iterator_t<R>, Proj>, const T*>
ranges::borrowed_subrange_t<R>
    find_last( Ep&& policy, R&& r, const T& value, Proj proj = {} );
(8) (seit C++26)
template< /*execution-policy*/ Ep,
          std::random_access_iterator I, std::sized_sentinel_for<I> S,
          class Proj = std::identity,
          std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
ranges::subrange<I> find_last_if( Ep&& policy, I first, S last,
                                  Pred pred, Proj proj = {} );
(9) (seit C++26)
template< /*execution-policy*/ Ep, /*sized-random-access-range*/ R,
          class Proj = std::identity,
          std::indirect_unary_predicate
              <std::projected<ranges::iterator_t<R>, Proj>> Pred >
ranges::borrowed_subrange_t<R>
    find_last_if( Ep&& policy, R&& r, Pred pred, Proj proj = {} );
(10) (seit C++26)
template< /*execution-policy*/ Ep,
          std::random_access_iterator I, std::sized_sentinel_for<I> S,
          class Proj = std::identity,
          std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
ranges::subrange<I> find_last_if_not( Ep&& policy, I first, S last,
                                      Pred pred, Proj proj = {} );
(11) (seit C++26)
template< /*execution-policy*/ Ep, /*sized-random-access-range*/ R,
          class Proj = std::identity,
          std::indirect_unary_predicate
              <std::projected<ranges::iterator_t<R>, Proj>> Pred >
ranges::borrowed_subrange_t<R>
    find_last_if_not( Ep&& policy, R&& r, Pred pred, Proj proj = {} );
(12) (seit C++26)

Für die Definition von /*execution-policy*/ siehe diese Seite; für die Definition von /*sized-random-access-range*/ siehe diese Seite.

Gibt das letzte Element (projiziert durch proj) im Quellbereich [first, last) oder r zurück, das bestimmte Kriterien erfüllt:

1,2) find_last sucht nach dem letzten Element, das gleich value ist.
3,4) find_last_if sucht nach dem letzten Element, für das das Prädikat pred true zurückgibt.
5,6) find_last_if_not sucht nach dem letzten Element, für das das Prädikat pred false zurückgibt.
7-12) Wie (1-6), aber ausgeführt gemäß policy.

Die auf dieser Seite beschriebenen funktionsartigen Entitäten sind Algorithmus-Funktionsobjekte (informell als Niebloids bekannt), das heißt:

Parameter

first, last - das Iterator-Sentinel-Paar, das den Quellbereich
definiert r -
der Quellbereich value -
der Zielwert pred -
das Prädikat, das auf die (projizierten) Elemente angewendet wird proj -
die Projektion, die auf die Elemente angewendet wird policy - die zu verwendende Ausführungsrichtlinie

Rückgabewert

Ein Teilbereich vom letzten Element, das die Bedingung erfüllt, bis zum Ende des Quellbereichs, oder ein leerer Bereich, wenn kein solches Element gefunden wird.

Komplexität

Gegeben N als ranges::distance(first, last) oder ranges::distance(r):

1,2) Höchstens N Vergleiche und Anwendungen von proj.
3-6) Höchstens N Anwendungen von pred und proj.
7,8) 𝓞(N) Vergleiche und Anwendungen von proj.
9-12) 𝓞(N) Anwendungen von pred und proj.

Ausnahmen

7-12) Während des Ausführungsprozesses:
  • Wenn die für die Parallelisierung erforderlichen temporären Speicherressourcen nicht verfügbar sind, wird std::bad_alloc ausgelöst.
  • Wenn eine nicht gefangene Ausnahme beim Zugriff auf Objekte über ein Algorithmusargument ausgelöst wird, wird das Verhalten durch die Ausführungsrichtlinie bestimmt (für Standardrichtlinien wird std::terminate aufgerufen).

Anmerkungen

ranges::find_last, ranges::find_last_if, ranges::find_last_if_not haben auf üblichen Implementierungen eine bessere Effizienz, wenn I bidirectional_iterator oder (besser) random_access_iterator modelliert.

Feature-Test-Makro Wert Std Funktion
__cpp_lib_ranges_find_last 202207L (C++23) ranges::find_last,
ranges::find_last_if,
ranges::find_last_if_not
__cpp_lib_algorithm_default_value_type 202403L (C++26) Listeninitialisierung für Algorithmen (1,2)

Mögliche Implementierung

Diese Implementierungen zeigen nur den langsameren Algorithmus, der verwendet wird, wenn I forward_iterator modelliert.

find_last
struct find_last_fn
{
    template<std::forward_iterator I, std::sentinel_for<I> S,
             class Proj = std::identity,
             class T = std::projected_value_t<ranges::iterator_t<R>, Proj>>
    requires std::indirect_binary_predicate
                 <ranges::equal_to, std::projected<I, Proj>, const T*>
    constexpr ranges::subrange<I>
        operator()(I first, S last, const T &value, Proj proj = {}) const
    {
        // Note: if I is mere forward_iterator, we may only go from begin to end.
        std::optional<I> found;
        for (; first != last; ++first)
            if (std::invoke(proj, *first) == value)
                found = first;
        
        if (!found)
            return {first, first};
        
        return {*found, ranges::next(*found, last)};
    }
    
    template<ranges::forward_range R,
             class Proj = std::identity,
             class T = std::projected_value_t<iterator_t<R>, Proj>>
    requires std::indirect_binary_predicate
                 <ranges::equal_to,
                  std::projected<ranges::iterator_t<R>, Proj>, const T*>
    constexpr ranges::borrowed_subrange_t<R>
        operator()(R&& r, const T &value, Proj proj = {}) const
    {
        return (*this)(ranges::begin(r),
                       ranges::next(ranges::begin(r), ranges::end(r)),
                       value, std::ref(proj));
    }
};

inline constexpr find_last_fn find_last;
find_last_if
struct find_last_if_fn
{
    template<std::forward_iterator I, std::sentinel_for<I> S,
             class Proj = std::identity,
             std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
    constexpr ranges::subrange<I>
        operator()(I first, S last, Pred pred, Proj proj = {}) const
    {
        // Note: if I is mere forward_iterator, we may only go from begin to end.
        std::optional<I> found;
        for (; first != last; ++first)
            if (std::invoke(pred, std::invoke(proj, *first)))
                found = first;
        
        if (!found)
            return {first, first};
        
        return {*found, ranges::next(*found, last)};
    }
    
    template<ranges::forward_range R, class Proj = std::identity,
             std::indirect_unary_predicate
                 <std::projected<ranges::iterator_t<R>, Proj>> Pred>
    constexpr ranges::borrowed_subrange_t<R>
        operator()(R&& r, Pred pred, Proj proj = {}) const
    {
        return (*this)(ranges::begin(r),
                       ranges::next(ranges::begin(r), ranges::end(r)),
                       std::ref(pred), std::ref(proj));
    }
};

inline constexpr find_last_if_fn find_last_if;
find_last_if_not
struct find_last_if_not_fn
{
    template<std::forward_iterator I, std::sentinel_for<I> S,
             class Proj = std::identity,
             std::indirect_unary_predicate<std::projected<I, Proj>> Pred>
    constexpr ranges::subrange<I>
        operator()(I first, S last, Pred pred, Proj proj = {}) const
    {
        // Note: if I is mere forward_iterator, we may only go from begin to end.
        std::optional<I> found;
        for (; first != last; ++first)
            if (!std::invoke(pred, std::invoke(proj, *first)))
                found = first;
        
        if (!found)
            return {first, first};
        
        return {*found, ranges::next(*found, last)};
    }
    
    template<ranges::forward_range R, class Proj = std::identity,
             std::indirect_unary_predicate
                 <std::projected<ranges::iterator_t<R>, Proj>> Pred>
    constexpr ranges::borrowed_subrange_t<R>
        operator()(R&& r, Pred pred, Proj proj = {}) const
    {
        return (*this)(ranges::begin(r),
                       ranges::next(ranges::begin(r), ranges::end(r)),
                       std::ref(pred), std::ref(proj));
    }
};

inline constexpr find_last_if_not_fn find_last_if_not;

Beispiel

#include <algorithm>
#include <cassert>
#include <forward_list>
#include <iomanip>
#include <iostream>
#include <string_view>

int main()
{
    namespace ranges = std::ranges;
    
    constexpr static auto v = {1, 2, 3, 1, 2, 3, 1, 2};
    
    {
        constexpr auto i1 = ranges::find_last(v.begin(), v.end(), 3);
        constexpr auto i2 = ranges::find_last(v, 3);
        static_assert(ranges::distance(v.begin(), i1.begin()) == 5);
        static_assert(ranges::distance(v.begin(), i2.begin()) == 5);
    }
    {
        constexpr auto i1 = ranges::find_last(v.begin(), v.end(), -3);
        constexpr auto i2 = ranges::find_last(v, -3);
        static_assert(i1.begin() == v.end());
        static_assert(i2.begin() == v.end());
    }
    
    auto abs = [](int x) { return x < 0 ? -x : x; };
    
    {
        auto pred = [](int x) { return x == 3; };
        constexpr auto i1 = ranges::find_last_if(v.begin(), v.end(), pred, abs);
        constexpr auto i2 = ranges::find_last_if(v, pred, abs);
        static_assert(ranges::distance(v.begin(), i1.begin()) == 5);
        static_assert(ranges::distance(v.begin(), i2.begin()) == 5);
    }
    {
        auto pred = [](int x) { return x == -3; };
        constexpr auto i1 = ranges::find_last_if(v.begin(), v.end(), pred, abs);
        constexpr auto i2 = ranges::find_last_if(v, pred, abs);
        static_assert(i1.begin() == v.end());
        static_assert(i2.begin() == v.end());
    }
    
    {
        auto pred = [](int x) { return x == 1 or x == 2; };
        constexpr auto i1 = ranges::find_last_if_not(v.begin(), v.end(), pred, abs);
        constexpr auto i2 = ranges::find_last_if_not(v, pred, abs);
        static_assert(ranges::distance(v.begin(), i1.begin()) == 5);
        static_assert(ranges::distance(v.begin(), i2.begin()) == 5);
    }
    {
        auto pred = [](int x) { return x == 1 or x == 2 or x == 3; };
        constexpr auto i1 = ranges::find_last_if_not(v.begin(), v.end(), pred, abs);
        constexpr auto i2 = ranges::find_last_if_not(v, pred, abs);
        static_assert(i1.begin() == v.end());
        static_assert(i2.begin() == v.end());
    }
    
    using P = std::pair<std::string_view, int>;
    std::forward_list<P> list
    {
        {"one", 1}, {"two", 2}, {"three", 3},
        {"one", 4}, {"two", 5}, {"three", 6},
    };
    auto cmp_one = [](const std::string_view &s) { return s == "one"; };
    
    // find latest element that satisfy the comparator, and projecting pair::first
    const auto subrange = ranges::find_last_if(list, cmp_one, &P::first);
    
    std::cout << "The found element and the tail after it are:\n";
    for (P const& e : subrange)
        std::cout << '{' << std::quoted(e.first) << ", " << e.second << "} ";
    std::cout << '\n';
    
#if __cpp_lib_algorithm_default_value_type
    const auto i3 = ranges::find_last(list, {"three", 3}); // (2) C++26
#else
    const auto i3 = ranges::find_last(list, P{"three", 3}); // (2) C++23
#endif
    assert(i3.begin()->first == "three" && i3.begin()->second == 3);
}

Ausgabe:

The found element and the tail after it are:
{"one", 4} {"two", 5} {"three", 6}

Siehe auch

findet die letzte Sequenz von Elementen in einem bestimmten Bereich
(Algorithmus-Funktionsobjekt)
findet das erste Element, das bestimmte Kriterien erfüllt
(Algorithmus-Funktionsobjekt)
sucht nach dem ersten Vorkommen eines Bereichs von Elementen
(Algorithmus-Funktionsobjekt)
bestimmt, ob eine Sequenz eine Untersequenz einer anderen ist
(Algorithmus-Funktionsobjekt)
bestimmt, ob ein Element in einem Bereich mittels binärer Suche vorhanden ist
(Algorithmus-Funktionsobjekt)
prüft, ob der Bereich das angegebene Element oder den angegebenen Teilbereich enthält
(Algorithmus-Funktionsobjekt)