Namespaces
Variants

std::ranges:: remove, std::ranges:: remove_if

From cppreference.net
Algorithm library
Constrained algorithms and algorithms on ranges (C++20)
Constrained algorithms, e.g. ranges::copy , ranges::sort , ...
Execution policies (C++17)
Non-modifying sequence operations
Batch operations
(C++17)
Search operations
Modifying sequence operations
Copy operations
(C++11)
(C++11)
Swap operations
Transformation operations
Generation operations
Removing operations
Order-changing operations
(until C++17) (C++11)
(C++20) (C++20)
Sampling operations
(C++17)

Sorting and related operations
Partitioning operations
Sorting operations
Binary search operations
(on partitioned ranges)
Set operations (on sorted ranges)
Merge operations (on sorted ranges)
Heap operations
Minimum/maximum operations
Lexicographical comparison operations
Permutation operations
C library
Numeric operations
Operations on uninitialized memory
Constrained algorithms
All names in this menu belong to namespace std::ranges
Non-modifying sequence operations
Modifying sequence operations
Partitioning operations
Sorting operations
Binary search operations (on sorted ranges)
Set operations (on sorted ranges)
Heap operations
Minimum/maximum operations
Permutation operations
Fold operations
Operations on uninitialized storage
Return types
Definido en el encabezado <algorithm>
Firma de llamada
(1)
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 = { } ) ;
(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)
(2)
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 = { } ) ;
(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 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.

1) Elimina todos los elementos que son iguales a value , utilizando std:: invoke ( proj, * i ) == value para comparar.
3) Elimina todos los elementos para los cuales std:: invoke ( pred, std:: invoke ( proj, * i ) ) devuelve true .
2,4) Igual que (1,3) , pero utiliza 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 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:

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

copia un rango de elementos omitiendo aquellos que cumplen criterios específicos
(objeto función de algoritmo)
elimina elementos duplicados consecutivos en un rango
(objeto función de algoritmo)
elimina elementos que cumplen criterios específicos
(plantilla de función)