std::ranges::remove, std::ranges::remove_if
| Definido en el encabezado <algorithm>
|
||
| Firma de llamada |
||
template< std::permutable 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>
remove( I first, S last, const T& value, Proj proj = {} );
|
(1) | (desde C++20) (hasta C++26) |
template< std::permutable 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>
remove( I first, S last, const T& value, Proj proj = {} );
|
(desde C++26) | |
template< ranges::forward_range R,
class T, class Proj = std::identity >
requires std::permutable<ranges::iterator_t<R>> &&
std::indirect_binary_predicate
<ranges::equal_to,
std::projected<ranges::iterator_t<R>, Proj>, const T*>
constexpr ranges::borrowed_subrange_t<R>
remove( R&& r, const T& value, Proj proj = {} );
|
(2) | (desde C++20) (hasta C++26) |
template< ranges::forward_range R,
class Proj = std::identity,
class T = std::projected_value_t<ranges::iterator_t<R>, Proj> >
requires std::permutable<ranges::iterator_t<R>> &&
std::indirect_binary_predicate
<ranges::equal_to,
std::projected<ranges::iterator_t<R>, Proj>, const T*>
constexpr ranges::borrowed_subrange_t<R>
remove( R&& r, const T& value, Proj proj = {} );
|
(desde C++26) | |
template< std::permutable I, std::sentinel_for<I> S,
class Proj = std::identity,
std::indirect_unary_predicate<std::projected<I, Proj>> Pred >
constexpr ranges::subrange<I>
remove_if( I first, S last, Pred pred, Proj proj = {} );
|
(3) | (desde C++20) |
template< ranges::forward_range R,
class Proj = std::identity,
std::indirect_unary_predicate
<std::projected<ranges::iterator_t<R>, Proj>> Pred >
requires std::permutable<ranges::iterator_t<R>>
constexpr ranges::borrowed_subrange_t<R>
remove_if( R&& r, Pred pred, Proj proj = {} );
|
(4) | (desde C++20) |
Elimina todos los elementos que satisfacen criterios específicos del rango [first, last) y devuelve un subrango [ret, last), donde ret es un iterador pasado el final para el nuevo final del rango.
value, usando std::invoke(proj, *i) == value para comparar.std::invoke(pred, std::invoke(proj, *i)) devuelve true.r como rango, como si usase ranges::begin(r) como first y ranges::end(r) como last.La eliminación se realiza desplazando (mediante asignación de movimiento) los elementos en el rango de tal manera que los elementos que no deben eliminarse aparecen al principio del rango. El orden relativo de los elementos que permanecen se conserva y el tamaño físico del contenedor no cambia. Los iteradores que apuntan a un elemento entre el nuevo final lógico y el final físico del rango aún se pueden desreferenciar, pero los elementos mismos tienen valores no especificados (según la postcondición de MoveAssignable).
Las entidades similares a funciones descritas en esta página son objetos función de algoritmo (conocidos informalmente como niebloids), es decir:
- No se pueden especificar listas de argumentos de plantilla explícitas al llamar a ninguna de ellas.
- Ninguna de ellas es visible mediante búsqueda dependiente de argumentos.
- Cuando alguna de ellas se encuentra mediante 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.
Parámetros
| first, last | - | el par iterador-centinela que define el rango de elementos a procesar |
| r | - | el rango de elementos a procesar |
| value | - | el valor de los elementos a eliminar |
| pred | - | predicado a aplicar a los elementos proyectados |
| proj | - | proyección a aplicar a los elementos |
Valor de retorno
{
ret, last
}
, donde
[
first
,
ret
)
es el subrango resultante después de la eliminación, y los elementos en el subrango
[
ret
,
last
)
están todos en un estado válido pero no especificado, es decir,
[
ret
,
last
)
es el subrango que debe ser borrado.
Complejidad
Exactamente N aplicaciones del predicado correspondiente y cualquier proyección, donde N = ranges:: distance ( first, last ) , y N - 1 operaciones de movimiento en el peor caso.
Notas
Una llamada a
ranges::remove
normalmente va seguida de una llamada a la función miembro
erase
del contenedor, que borra los valores no especificados y reduce el
tamaño físico
del contenedor para que coincida con su nuevo
tamaño lógico
. Estas dos invocaciones juntas constituyen el llamado
erase-remove idiom
, que puede lograrse mediante la función libre
std::erase
que tiene
sobrecargas
para todos los contenedores estándar
de secuencia
, o
std::erase_if
que tiene
sobrecargas
para
todos
los contenedores estándar.
Las funciones miembro de contenedores con nombres similares member functions list::remove , list::remove_if , forward_list::remove , y forward_list::remove_if eliminan los elementos removidos.
Estos algoritmos generalmente no pueden utilizarse con contenedores asociativos como std::set y std::map porque sus tipos de iterador no desreferencian a tipos MoveAssignable (las claves en estos contenedores no son modificables).
Debido a que
ranges::remove
toma el
value
por referencia, puede tener un comportamiento inesperado si es una referencia a un elemento del rango
[
first
,
last
)
.
Implementación posible
| remove (1,2) |
|---|
struct remove_fn { template<std::permutable 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> operator()(I first, S last, const T& value, Proj proj = {}) const { first = ranges::find(std::move(first), last, value, proj); if (first != last) { for (I i{std::next(first)}; i != last; ++i) if (value != std::invoke(proj, *i)) { *first = ranges::iter_move(i); ++first; } } return {first, last}; } template<ranges::forward_range R, class Proj = std::identity, class T = std::projected_value_t<ranges::iterator_t<R>, Proj>> requires std::permutable<ranges::iterator_t<R>> && 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::end(r), value, std::move(proj)); } }; inline constexpr remove_fn remove {}; |
| remove_if (3,4) |
struct remove_if_fn { template<std::permutable I, std::sentinel_for<I> S, class Proj = std::identity, std::indirect_unary_predicate<std::projected<I, Proj>> Pred> constexpr ranges::subrange<I> operador()(I primero, S último, Pred pred, Proj proj = {}) const { primero = ranges::find_if(std::move(primero), último, pred, proj); if (primero != último) { for (I i{std::next(primero)}; i != último; ++i) if (!std::invoke(pred, std::invoke(proj, *i))) { *primero = ranges::iter_move(i); ++primero; } } return {primero, último}; } template<ranges::forward_range R, class Proj = std::identity, std::indirect_unary_predicate <std::projected<ranges::iterator_t<R>, Proj>> Pred> requires std::permutable<ranges::iterator_t<R>> constexpr ranges::borrowed_subrange_t<R> operador()(R&& r, Pred pred, Proj proj = {}) const { return (*this)(ranges::begin(r), ranges::end(r), pred, std::move(proj)); } }; inline constexpr remove_if_fn remove_if {}; |
Notas
| Macro de prueba de características | Valor | Estándar | Característica |
|---|---|---|---|
__cpp_lib_algorithm_default_value_type
|
202403
|
(C++26) | Inicialización por lista para algoritmos ( 1,2 ) |
Ejemplo
#include <algorithm> #include <cassert> #include <complex> #include <cctype> #include <iomanip> #include <iostream> #include <string> #include <string_view> #include <vector> int main() { std::string v1{"No se requiere diagnóstico"}; std::cout << std::quoted(v1) << " (v1, tamaño: " << v1.size() << ")\n"; const auto ret = std::ranges::remove(v1, ' '); std::cout << std::quoted(v1) << " (v1 después de `remove`, tamaño: " << v1.size() << ")\n"; std::cout << ' ' << std::string(std::distance(v1.begin(), ret.begin()), '^') << '\n'; v1.erase(ret.begin(), ret.end()); std::cout << std::quoted(v1) << " (v1 después de `erase`, tamaño: " << v1.size() << ")\n\n"; // remove_if con predicado unario personalizado: auto rm = [](char c) { return !std::isupper(c); }; std::string v2{"Substitution Failure Is Not An Error"}; std::cout << std::quoted(v2) << " (v2, tamaño: " << v2.size() << ")\n"; const auto [first, last] = std::ranges::remove_if(v2, rm); std::cout << std::quoted(v2) << " (v2 después de `remove_if`, tamaño: " << v2.size() << ")\n"; std::cout << ' ' << std::string(std::distance(v2.begin(), first), '^') << '\n'; v2.erase(first, last); std::cout << std::quoted(v2) << " (v2 después de `erase`, tamaño: " << v2.size() << ")\n\n"; // creando una vista en un contenedor que es modificado por `remove_if`: for (std::string s : {"Optimización de Objetos Pequeños", "Parámetro de Plantilla No Tipo"}) std::cout << std::quoted(s) << " => " << std::string_view{begin(s), std::ranges::remove_if(s, rm).begin()} << '\n'; std::vector<std::complex<double>> nums{{2, 2}, {1, 3}, {4, 8}}; #ifdef __cpp_lib_algorithm_default_value_type auto e = std::ranges::remove(nums, {1, 3}); // T se deduce #else auto e = std::ranges::remove(nums, std::complex<double>{1, 3}); #endif nums.erase(e.begin(), e.end()); assert((nums == std::vector<std::complex<double>>{{2, 2}, {4, 8}})); }
Salida posible:
"No _ Diagnostic _ Required" (v1, tamaño: 26) "No_Diagnostic_Requiredired" (v1 después de `remove`, tamaño: 26) ^^^^^^^^^^^^^^^^^^^^^^ "No_Diagnostic_Required" (v1 después de `erase`, tamaño: 22) "Substitution Failure Is Not An Error" (v2, tamaño: 36) "SFINAEtution Failure Is Not An Error" (v2 después de `remove_if`, tamaño: 36) ^^^^^^ "SFINAE" (v2 después de `erase`, tamaño: 6) "Small Object Optimization" => SOO "Non-Type Template Parameter" => NTTP
Véase también
|
(C++20)
(C++20)
|
copia un rango de elementos omitiendo aquellos que cumplen criterios específicos
(objeto función de algoritmo) |
|
(C++20)
|
elimina elementos duplicados consecutivos en un rango
(objeto función de algoritmo) |
|
elimina elementos que cumplen criterios específicos
(plantilla de función) |