std::ranges::find_last, std::ranges::find_last_if, std::ranges::find_last_if_not
De cppreference.com
<tbody>
</tbody>
| 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 [first, last) 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 [first, last) cuyo predicado pred devuelve true.5)
find_last_if_not busca el último elemento en el rango [first, last) 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:
- Las listas de argumentos de plantilla explícitas no se pueden especificar al llamar a cualquiera de ellas.
- Ninguna de ellas es visible para la búsqueda dependiente de argumentos.
- Cuando alguna de ellas se encuentra mediante la búsqueda normal no calificada como el nombre a la izquierda del operador de llamada a función, se inhibe la búsqueda dependiente de argumentos.
En la práctica, pueden implementarse como objetos función o con extensiones de compilador especiales.
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. |
Valor de retorno
1,2,3) Sea
i el último iterador en el rango [first, last) 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>.Complejidad
A lo sumo last - first aplicaciones del predicado y proyección.
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
|
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;
|
Ejemplo
Un enlace a probar: Compiler Explorer/g++-trunk
Ejecuta este código
#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}
Véase también
(C++20) |
Encuentra la última secuencia de elementos en un cierto rango. (niebloid) |
(C++20)(C++20)(C++20) |
Encuentra el primer elemento que satisfaga un criterio específico. (niebloid) |
(C++20) |
Busca una subsecuencia de elementos en un rango. (niebloid) |
(C++20) |
Devuelve true si una secuencia es una subsecuencia de otra. (niebloid) |
(C++20) |
Determina si un elemento existe en un cierto rango. (niebloid) |
(C++23)(C++23) |
Comprueba si el rango contiene el elemento dado o un subrango. (niebloid) |