std::ranges::remove, std::ranges::remove_if
| Definido en el archivo de encabezado <algorithm>
|
||
| Signatura de la 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) |
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) |
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 un criterio específico 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 el rango, como si usara ranges::begin(r) como first y ranges::end(r) como last.La eliminación se realiza desplazando (mediante la asignación de movimiento) los elementos del rango de forma que los elementos que no se van a eliminar aparezcan al principio del rango. Se conserva el orden relativo de los elementos que quedan 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 desreferenciables, pero los elementos en sí tienen valores no especificados (según la poscondición de MoveAssignable).
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 elementos a procesar. |
| r | - | El rango de elementos a procesar. |
| value | - | El valor de los elementos a eliminar.. |
| pred | - | El predicado para aplicar a los elementos proyectados. |
| proj | - | La proyección para 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.
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 de los casos.
Notas
Una llamada a ranges::remove suele ir seguida de una llamada a la función miembro erase de un 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 modismo Erase–remove, que se puede lograr 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 contenedor de nombre similar, list::remove, list::remove_if, forward_list::remove, y forward_list::remove_if borran los elementos eliminados.
Estos algoritmos no se pueden usar con contenedores asociativos como std::set y std::map porque sus tipos iterador no eliminan la referencia a los tipos MoveAssignable (las claves en estos contenedores no son modificables).
Debido a que std::remove toma value por referencia, puede tener un comportamiento inesperado si es una referencia a un elemento del rango [first, last).
Posible implementación
| remove |
|---|
struct remove_fn
{
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>
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 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>
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 |
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>
operator()(I first, S last, Pred pred, Proj proj = {}) const
{
first = ranges::find_if(std::move(first), last, pred, proj);
if (first != last)
{
for (I i {std::next(first)}; i != last; ++i)
{
if (!std::invoke(pred, std::invoke(proj, *i)))
{
*first = ranges::iter_move(i);
++first;
}
}
}
return {first, last};
}
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>
operator()(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 {};
|
Ejemplo
#include <algorithm>
#include <cctype>
#include <iomanip>
#include <iostream>
#include <string>
#include <string_view>
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 {"Falla En La Sustitución No Es Un 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";
// se crea una vista sobre cadena dentro de un contenedor que se modifica por `remove_if`:
for (std::string s : {"Optimización de Objeto Pequeño", "Parámetro de Plantilla de No Tipo"})
std::cout << std::quoted(s) << " => "
<< std::string_view {begin(s), std::ranges::remove_if(s, rm).begin()}
<< '\n';
}
Posible salida:
"No - se requiere - diagnóstico" (v1, tamaño: 31)
"No-serequiere-diagnósticostico" (v1 después de `remove`, tamaño: 31)
^^^^^^^^^^^^^^^^^^^^^^^^^^
"No-serequiere-diagnóstico" (v1 después de `erase`, tamaño: 26)
"Falla En La Sustitución No Es Un Error" (v2, tamaño: 39)
"FELSNEUE La Sustitución No Es Un Error" (v2 después de `remove_if`, tamaño: 39)
^^^^^^^^
"FELSNEUE" (v2 después de `erase`, tamaño: 8)
"Optimización de Objeto Pequeño" => OOP
"Parámetro de Plantilla de No Tipo" => PPNT
Véase también
(C++20)(C++20) |
Copia un rango de elementos, omitiendo aquellos que satisfacen un criterio específico (niebloid) |
(C++20) |
Elimina elementos duplicados consecutivos en un rango. (niebloid) |
| Elimina elementos que satisfacen un criterio específico. (plantilla de función) |