std::ranges:: remove, std::ranges:: remove_if
|
Definido en el encabezado
<algorithm>
|
||
|
Firma de llamada
|
||
| (1) | ||
|
template
<
std::
permutable
I,
std::
sentinel_for
<
I
>
S,
class
T,
class
Proj
=
std::
identity
>
|
(desde C++20)
(hasta C++26) |
|
|
template
<
std::
permutable
I,
std::
sentinel_for
<
I
>
S,
class
Proj
=
std::
identity
,
|
(desde C++26) | |
| (2) | ||
|
template
<
ranges::
forward_range
R,
class
T,
class
Proj
=
std::
identity
>
|
(desde C++20)
(hasta C++26) |
|
|
template
<
ranges::
forward_range
R,
class
Proj
=
std::
identity
,
|
(desde C++26) | |
|
template
<
std::
permutable
I,
std::
sentinel_for
<
I
>
S,
class
Proj
=
std::
identity
,
|
(3) | (desde C++20) |
|
template
<
ranges::
forward_range
R,
class
Proj
=
std::
identity
,
|
(4) | (desde C++20) |
Elimina todos los elementos que cumplen criterios específicos del rango
[
first
,
last
)
y devuelve un subrango
[
ret
,
last
)
, donde
ret
es un iterador más allá del final para el nuevo extremo del rango.
La eliminación se realiza desplazando (mediante asignación de movimiento) los elementos en el rango de tal manera que los elementos que no se deben eliminar 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 siguen siendo dereferenciables, pero los elementos mismos tienen valores no especificados (según la MoveAssignable post-condición).
Las entidades similares a funciones descritas en esta página son algorithm function objects (conocidas informalmente como niebloids ), es decir:
- No se pueden especificar listas de argumentos de plantilla explícitas al llamar a cualquiera de ellos.
- Ninguno de ellos es visible para la búsqueda dependiente de argumento .
- Cuando cualquiera de ellos es encontrado mediante la búsqueda no calificada normal como el nombre a la izquierda del operador de llamada a función, la búsqueda dependiente de argumento queda inhibida.
Contenidos |
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) |