std::ranges::remove, std::ranges::remove_if
| Определён в заголовке <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 — это итератор, указывающий за конец нового конца диапазона.
value, используя std::invoke(proj, *i) == value для сравнения.std::invoke(pred, std::invoke(proj, *i)) возвращает true.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) |
|---|
| удалить (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
Смотрите также
|
(C++20)
(C++20)
|
копирует диапазон элементов, исключая те, которые удовлетворяют определённым критериям
(функциональный объект алгоритма) |
|
(C++20)
|
удаляет последовательные дублирующиеся элементы в диапазоне
(функциональный объект алгоритма) |
|
удаляет элементы, удовлетворяющие определённым критериям
(шаблон функции) |