Namespaces
Variants

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

С ru.cppreference.net
 
 
Библиотека алгоритмов
Ограниченные алгоритмы и алгоритмы над диапазонами (C++20)
Ограниченные алгоритмы, например ranges::copy, ranges::sort, ...
Операции последовательности, не изменяющие её    
Пакетные операции
(C++17)
Операции поиска
Операции последовательности, изменяющие её
Операции копирования
(C++11)
(C++11)
Операции обмена
Операции преобразования
Операции генерации
Операции удаления
Операции изменения порядка
(до C++17)(C++11)
(C++20)(C++20)
Операции выборки
(C++17)

Сортировка и связанные операции
Операции разделения
(C++11)    

Операции сортировки
Операции двоичного поиска
(на разделённых диапазонах)
Операции над множествами (на отсортированных диапазонах)
Операции слияния (на отсортированных диапазонах)
Операции с кучей
Операции минимума/максимума
(C++11)
(C++17)
Операции лексикографического сравнения
Операции перестановки


Политики выполнения (C++17)
(только для пояснения*)(C++26)

Численные операции
(C++11)
(C++17)
(C++17)    

Специализированные <memory> алгоритмы

Специализированные <random> алгоритмы
Библиотека C









 
Ограниченные алгоритмы
Все имена в этом меню принадлежат пространству имён std::ranges
Операции последовательности, не изменяющие её
Операции последовательности, изменяющие её
Операции разделения
Операции сортировки
Операции двоичного поиска (на отсортированных диапазонах)
       
       
Операции над множествами (на отсортированных диапазонах)
Операции с кучей
Операции минимума/максимума
       
       
Операции перестановки
Операции свёртки
Операции над неинициализированной памятью
Типы возврата
 
Определён в заголовке <algorithm>
Сигнатура вызова
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) (начиная с C++20)
(до 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 = {} );
(начиная с 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) (начиная с C++20)
(до 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 = {} );
(начиная с 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) (начиная с 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) (начиная с C++20)

Удаляет все элементы, удовлетворяющие определённым критериям, из диапазона [first, last) и возвращает поддиапазон [ret, last), где ret — это итератор, указывающий за конец нового конца диапазона.

1) Удаляет все элементы, равные value, используя std::invoke(proj, *i) == value для сравнения.
3) Удаляет все элементы, для которых std::invoke(pred, std::invoke(proj, *i)) возвращает true.
2,4) То же, что и (1,3), но использует r в качестве диапазона, как если бы ranges::begin(r) использовался как first, а ranges::end(r) как last.

Удаление выполняется путём сдвига (посредством перемещающего присваивания) элементов в диапазоне таким образом, что элементы, которые не подлежат удалению, оказываются в начале диапазона. Относительный порядок оставшихся элементов сохраняется, а физический размер контейнера не изменяется. Итераторы, указывающие на элемент между новым логическим концом и физическим концом диапазона, всё ещё можно разыменовывать, но сами элементы имеют неопределённые значения (в соответствии с постусловием MoveAssignable).

Функциональные объекты, описанные на этой странице, представляют собой алгоритмические функциональные объекты (неформально известные как niebloids), а именно:

Параметры

first, last - пара итератор-страж, определяющая диапазон обрабатываемых элементов
r - диапазон обрабатываемых элементов
value - значение элементов для удаления
pred - предикат, применяемый к проецируемым элементам
proj - проекция, применяемая к элементам

Возвращаемое значение

{ ret, last } , где [ first , ret ) является результирующим поддиапазоном после удаления, а элементы в поддиапазоне [ ret , last ) находятся в допустимом, но неопределённом состоянии, т.е. [ ret , last ) является поддиапазоном для удаления.

Сложность

Ровно N применений соответствующего предиката и любой проекции, где N = ranges:: distance ( first, last ) , и N - 1 операций перемещения в худшем случае.

Примечания

Вызов ranges::remove обычно сопровождается вызовом функции-члена erase контейнера, которая удаляет неопределённые значения и уменьшает физический размер контейнера в соответствии с его новым логическим размером. Эти два вызова вместе образуют так называемый идиому erase-remove , который может быть достигнут с помощью свободной функции std::erase , имеющей перегрузки для всех стандартных последовательных контейнеров, или std::erase_if , которая имеет перегрузки для всех стандартных контейнеров.

Аналогично названные контейнерные функции-члены list::remove , list::remove_if , forward_list::remove и forward_list::remove_if удаляют убранные элементы.

Эти алгоритмы обычно нельзя использовать с ассоциативными контейнерами, такими как std::set и std::map , поскольку их типы итераторов не разыменовываются в MoveAssignable типы (ключи в этих контейнерах не могут быть изменены).

Поскольку ranges::remove принимает value по ссылке, это может привести к неожиданному поведению, если это ссылка на элемент диапазона [ first , last ) .

Возможная реализация

Перевод: Примечание: Слово "remove" переведено как "удалить" в соответствии с контекстом функций/команд, сохраняя при этом числовые параметры (1,2) без изменений. HTML-теги и атрибуты сохранены в оригинальном виде. **Примечание:** Весь код C++ внутри тегов `
` и `` оставлен без изменений, как и требовалось. HTML-теги и атрибуты также сохранены в оригинальном виде.
remove (1,2)
удалить (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>
        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 {};

Примечания

Макрос тестирования возможностей Значение Стандарт Возможность
__cpp_lib_algorithm_default_value_type 202403 (C++26) Списковая инициализация для алгоритмов ( 1,2 )

Пример

#include <algorithm>
#include <cassert>
#include <complex>
#include <cctype>
#include <iomanip>
#include <iostream>
#include <string>
#include <string_view>
#include <vector>
int main()
{
    std::string v1{"Диагностика не требуется"};
    std::cout << std::quoted

(Примечание: Согласно требованиям, HTML-теги и атрибуты не переведены, термин `std::quoted` как специфический для C++ оставлен без перевода)(v1) << " (v1, размер: " << v1.size() << ")\n";
    const auto ret = std::ranges::удалить(v1, ' ');
    std::cout << std::quoted

(Примечание: Согласно требованиям, HTML-теги и атрибуты не переведены, термин `std::quoted` как специфический для C++ оставлен без перевода)(v1) << " (v1 после `remove`, размер: " << v1.size() << ")\n";
    std::cout << ' ' << std::string(std::distance(v1.begin(), ret.begin()), '^') << '\n';
    v1.erase(ret.begin(), ret.end());
    std::cout << std::quoted

(Примечание: Согласно требованиям, HTML-теги и атрибуты не переведены, термин `std::quoted` как специфический для C++ оставлен без перевода)(v1) << " (v1 после `erase`, размер: " << v1.size() << ")\n\n";
    // remove_if с пользовательским унарным предикатом:
    auto rm = [](char c) { return !std::isupper(c); };
    std::string v2{"Substitution Failure Is Not An Error"};
    std::cout << std::quoted

(Примечание: В соответствии с инструкциями, HTML-теги, атрибуты и C++ специфичные термины (включая `std::quoted`) не переведены. Весь переводимый текст отсутствует, кроме самого термина, который оставлен без изменений)(v2) << " (v2, размер: " << v2.size() << ")\n";
    const auto [first, last] = std::ranges::remove_if(v2, rm);
    std::cout << std::quoted

(Примечание: Согласно требованиям, HTML-теги и атрибуты не переведены, термин `std::quoted` как специфический для C++ оставлен без перевода)(v2) << " (v2 после `remove_if`, размер: " << v2.size() << ")\n";
    std::cout << ' ' << std::string(std::distance(v2.begin(), first), '^') << '\n';
    v2.erase(first, last);
    std::cout << std::quoted(v2) << " (v2 после `erase`, размер: " << v2.size() << ")\n\n";
    // создание представления в контейнере, который модифицируется с помощью `remove_if`:
    for (std::string s : {"Оптимизация малых объектов", "Параметр шаблона без типа"})
        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::удалить(nums, {1, 3}); // T выводится
    #else
        auto e = std::ranges::удалить(nums, std::complex<double>{1, 3});
    #endif
    nums.erase(e.begin(), e.end());
    assert((nums == std::vector<std::complex<double>>{{2, 2}, {4, 8}}));
}

Возможный вывод:

"No _ Diagnostic _ Required" (v1, размер: 26)
"No_Diagnostic_Requiredired" (v1 после `remove`, размер: 26)
 ^^^^^^^^^^^^^^^^^^^^^^
"No_Diagnostic_Required" (v1 после `erase`, размер: 22)
"Substitution Failure Is Not An Error" (v2, размер: 36)
"SFINAEtution Failure Is Not An Error" (v2 после `remove_if`, размер: 36)
 ^^^^^^
"SFINAE" (v2 после `erase`, размер: 6)
"Small Object Optimization" => SOO
"Non-Type Template Parameter" => NTTP

Смотрите также

копирует диапазон элементов, исключая те, которые удовлетворяют определённым критериям
(функциональный объект алгоритма)
удаляет последовательные дублирующиеся элементы в диапазоне
(функциональный объект алгоритма)
удаляет элементы, удовлетворяющие определённым критериям
(шаблон функции)