Espacios de nombres
Variantes
Acciones

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

De cppreference.com
< cpp‎ | algorithm‎ | ranges
 
 
Biblioteca de algoritmos
Políticas de ejecución (C++17)
Operaciones de secuencia no modificantes
(C++11)(C++11)(C++11)
(C++17)
Operaciones de secuencia modificantes
Operaciones en almacenamiento no inicializado
Operaciones de partición
Operaciones de ordenación
(C++11)
Operaciones de búsqueda binaria
Operaciones de conjuntos (en rangos ordenados)
Operaciones de pila
(C++11)
Operaciones mínimo/máximo
(C++11)
(C++17)
Permutaciones
Operaciones numéricas
Bibliotecas C
 
Algoritmos restringidos
Operaciones de secuencia no modificantes
Operaciones de secuencia modificantes
Operaciones en almacenamiento sin inicializar
Operaciones de partición
Operaciones de ordenamiento
Operaciones de búsqueda binaria
Operaciones de conjuntos (en rangos ordenados)
Operaciones de montículo/montón
Operaciones de mínimo/máximo
Permutaciones
 
Definido en el archivo de encabezado <algorithm>
Signatura de la llamada
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) (desde C++23)
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) (desde 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( I first, S last, Pred pred, Proj proj = {} );
(3) (desde 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) (desde 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) (desde 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) (desde C++23)

Devuelve el último elemento en el rango [firstlast) que satisface criterios específicos:

1) find_last busca un elemento igual a value.
3) find_last_if busca el último elemento en el rango [firstlast) cuyo predicado pred devuelve true.
5) find_last_if_not busca el último elemento en el rango [firstlast) cuyo predicado pred devuelve false.
2,4,6) Igual que (1,3,5), pero usa r como el rango fuente, como si usara ranges::begin(r) como first y ranges::end(r) como last.

Las entidades similares a funciones descritas en esta página son niebloids, es decir:

En la práctica, pueden implementarse como objetos función o con extensiones de compilador especiales.

Contenido

[editar] Parámetros

first, last - El rango de los elementos a examinar.
r - El rango de los elementos a examinar.
value - El valor con el que comparar los elementos.
pred - Predicado a aplicar a los elementos proyectados.
proj - Proyección a aplicar a los elementos.

[editar] Valor de retorno

1,2,3) Sea i el último iterador en el rango [firstlast) para el cual E es true. Devuelve ranges::subrange<I>{i, last}, o ranges::subrange<I>{last, last} si no se encuentra tal iterador.
2,4,6) Igual que (1,2,3) pero el tipo de retorno es ranges::borrowed_subrange_t<I>.

[editar] Complejidad

A lo sumo last - first aplicaciones del predicado y proyección.

[editar] Notas

ranges::find_last, ranges::find_last_if, ranges::find_last_if_not tienen una mejor eficiencia en implementaciones comunes si I modela bidirectional_iterator o (mejor) random_access_iterator.


Macro de Prueba de característica Valor Estándar Comentario
__cpp_lib_ranges_find_last 202207L (C++23) ranges::find_last, ranges::find_last_if, ranges::find_last_if_not

[editar] Posible implementación

Estas implementaciones solo muestran el algoritmo más lento que se usa cuando I modela forward_iterator.

find_last (1-2)
struct find_last_fn
{
    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>
        operator()(I first, S last, const T &value, Proj proj = {}) const
    {
        // Nota: si I es un mero forward_iterator, solo podemos ir de principio a fin.
        I found {};
        for (; first != last; ++first)
            if (std::invoke(proj, *first) == value)
                found = first;
 
        if (found == I {})
            return {first, first};
 
        return {found, std::ranges::next(found, last)};
    }
 
    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>
        operator()(R&& r, const T &value, Proj proj = {}) const
    {
        return this->operator()(ranges::begin(r), ranges::end(r), value, std::ref(proj));
    }
};
 
inline constexpr find_last_fn find_last;
find_last_if (3-4)
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
    {
        // Nota: si I es un mero forward_iterator, solo podemos ir de principio a fin.
        I found {};
        for (; first != last; ++first)
            if (std::invoke(pred, std::invoke(proj, *first)))
                found = first;
 
        if (found == I {})
            return {first, first};
 
        return {found, std::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->operator()(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 (5-6)
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
    {
        // Nota: si I es un mero forward_iterator, solo podemos ir de principio a fin.
        I found {};
        for (; first != last; ++first)
            if (!std::invoke(pred, std::invoke(proj, *first)))
                found = first;
 
        if (found == I {})
            return {first, first};
 
        return {found, std::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->operator()(ranges::begin(r), ranges::end(r),
                                std::ref(pred), std::ref(proj));
    }
};
 
inline constexpr find_last_if_not_fn find_last_if_not;

[editar] Ejemplo

Un enlace a probar: Compiler Explorer/g++-trunk

#include <algorithm>
#include <forward_list>
#include <iomanip>
#include <iostream>
#include <string_view>
 
int main()
{
    constexpr static auto v = {1, 2, 3, 1, 2, 3, 1, 2};
 
    {
        constexpr auto i1 = std::ranges::find_last(v.begin(), v.end(), 3);
        constexpr auto i2 = std::ranges::find_last(v, 3);
        static_assert(std::ranges::distance(v.begin(), i1.begin()) == 5);
        static_assert(std::ranges::distance(v.begin(), i2.begin()) == 5);
    }
    {
        constexpr auto i1 = std::ranges::find_last(v.begin(), v.end(), -3);
        constexpr auto i2 = std::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 = std::ranges::find_last_if(v.begin(), v.end(), pred, abs);
        constexpr auto i2 = std::ranges::find_last_if(v, pred, abs);
        static_assert(std::ranges::distance(v.begin(), i1.begin()) == 5);
        static_assert(std::ranges::distance(v.begin(), i2.begin()) == 5);
    }
    {
        auto pred = [](int x) { return x == -3; };
        constexpr auto i1 = std::ranges::find_last_if(v.begin(), v.end(), pred, abs);
        constexpr auto i2 = std::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 = std::ranges::find_last_if_not(v.begin(), v.end(), pred, abs);
        constexpr auto i2 = std::ranges::find_last_if_not(v, pred, abs);
        static_assert(std::ranges::distance(v.begin(), i1.begin()) == 5);
        static_assert(std::ranges::distance(v.begin(), i2.begin()) == 5);
    }
    {
        auto pred = [](int x) { return x == 1 or x == 2 or x == 3; };
        constexpr auto i1 = std::ranges::find_last_if_not(v.begin(), v.end(), pred, abs);
        constexpr auto i2 = std::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"; };
 
    // encuentra el último elemento que satisfaga el comparador y proyecta pair::first
    const auto subrange = std::ranges::find_last_if(list, cmp_one, &P::first);
 
    // imprime el elemento encontrado y el la "cola" que le sigue
    for (P const& e : subrange)
        std::cout << '{' << std::quoted(e.first) << ", " << e.second << "} ";
    std::cout << '\n';
}

Salida:

{"one", 4} {"two", 5} {"three", 6}

[editar] Véase también

Encuentra la última secuencia de elementos en un cierto rango.
(niebloid) [editar]
Encuentra el primer elemento que satisfaga un criterio específico.
(niebloid) [editar]
Busca una subsecuencia de elementos en un rango.
(niebloid) [editar]
Devuelve true si una secuencia es una subsecuencia de otra.
(niebloid) [editar]
Determina si un elemento existe en un cierto rango.
(niebloid) [editar]
Comprueba si el rango contiene el elemento dado o un subrango.
(niebloid) [editar]