std::ranges:: remove, std::ranges:: remove_if
|
Definiert im Header
<algorithm>
|
||
|
Aufrufsignatur
|
||
| (1) | ||
|
template
<
std::
permutable
I,
std::
sentinel_for
<
I
>
S,
class
T,
class
Proj
=
std::
identity
>
|
(seit C++20)
(bis C++26) |
|
|
template
<
std::
permutable
I,
std::
sentinel_for
<
I
>
S,
class
Proj
=
std::
identity
,
|
(seit C++26) | |
| (2) | ||
|
template
<
ranges::
forward_range
R,
class
T,
class
Proj
=
std::
identity
>
|
(seit C++20)
(bis C++26) |
|
|
template
<
ranges::
forward_range
R,
class
Proj
=
std::
identity
,
|
(seit C++26) | |
|
template
<
std::
permutable
I,
std::
sentinel_for
<
I
>
S,
class
Proj
=
std::
identity
,
|
(3) | (seit C++20) |
|
template
<
ranges::
forward_range
R,
class
Proj
=
std::
identity
,
|
(4) | (seit C++20) |
Entfernt alle Elemente, die bestimmte Kriterien erfüllen, aus dem Bereich
[
first
,
last
)
und gibt einen Teilbereich
[
ret
,
last
)
zurück, wobei
ret
ein Past-the-End-Iterator für das neue Ende des Bereichs ist.
Das Entfernen erfolgt durch Verschieben (mittels Move-Zuweisung) der Elemente im Bereich in einer Weise, dass die nicht zu entfernenden Elemente am Anfang des Bereichs erscheinen. Die relative Reihenfolge der verbleibenden Elemente bleibt erhalten und die physische Größe des Containers ändert sich nicht. Iteratoren, die auf ein Element zwischen dem neuen logischen Ende und dem physischen Ende des Bereichs zeigen, sind weiterhin dereferenzierbar, aber die Elemente selbst haben unspezifizierte Werte (gemäß der MoveAssignable Nachbedingung).
Die auf dieser Seite beschriebenen funktionsähnlichen Entitäten sind Algorithm Function Objects (informell bekannt als Niebloids ), das heißt:
- Explizite Template-Argumentlisten können beim Aufruf keiner von ihnen angegeben werden.
- Keiner von ihnen ist sichtbar für argument-dependent lookup .
- Wenn einer von ihnen durch normal unqualified lookup als Name links vom Funktionsaufrufoperator gefunden wird, wird argument-dependent lookup unterdrückt.
Inhaltsverzeichnis |
Parameter
| first, last | - | das Iterator-Sentinel-Paar, das den Bereich der zu verarbeitenden Elemente definiert |
| r | - | der Bereich der zu verarbeitenden Elemente |
| value | - | der Wert der zu entfernenden Elemente |
| pred | - | Prädikat, das auf die projizierten Elemente angewendet wird |
| proj | - | Projektion, die auf die Elemente angewendet wird |
Rückgabewert
{
ret, last
}
, wobei
[
first
,
ret
)
der resultierende Teilbereich nach der Entfernung ist, und die Elemente im Teilbereich
[
ret
,
last
)
sich alle in einem gültigen aber unspezifizierten Zustand befinden, d.h.
[
ret
,
last
)
ist der zu löschende Teilbereich.
Komplexität
Genau N Anwendungen des entsprechenden Prädikats und jeglicher Projektion, wobei N = ranges:: distance ( first, last ) , und N - 1 Move-Operationen im schlimmsten Fall.
Hinweise
Ein Aufruf von
ranges::remove
wird typischerweise gefolgt von einem Aufruf der
erase
-Memberfunktion eines Containers, welche die unspezifizierten Werte löscht und die
physische
Größe des Containers an die neue
logische
Größe anpasst. Diese beiden Aufrufe bilden zusammen das sogenannte
Erase-Remove-Idiom
, das durch die freie Funktion
std::erase
erreicht werden kann, die
Überladungen
für alle standardmäßigen
Sequenz
-Container besitzt, oder durch
std::erase_if
, das
Überladungen
für
alle
standardmäßigen Container bereitstellt.
Die ähnlich benannten Container- Memberfunktionen list::remove , list::remove_if , forward_list::remove und forward_list::remove_if löschen die entfernten Elemente.
Diese Algorithmen können in der Regel nicht mit assoziativen Containern wie std::set und std::map verwendet werden, da ihre Iteratortypen nicht auf MoveAssignable -Typen dereferenzieren (die Schlüssel in diesen Containern sind nicht veränderbar).
Da
ranges::remove
den
value
als Referenz übernimmt, kann es unerwartetes Verhalten verursachen, falls es sich um eine Referenz auf ein Element des Bereichs
[
first
,
last
)
handelt.
Mögliche Implementierung
| entfernen (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 {}; |
Hinweise
| Feature-Test Makro | Wert | Std | Feature |
|---|---|---|---|
__cpp_lib_algorithm_default_value_type
|
202403
|
(C++26) | Listeninitialisierung für Algorithmen ( 1,2 ) |
Beispiel
#include <algorithm> #include <cassert> #include <complex> #include <cctype> #include <iomanip> #include <iostream> #include <string> #include <string_view> #include <vector> int main() { std::string v1{"Keine - Diagnose - Erforderlich"}; std::cout << std::quoted(v1) << " (v1, Größe: " << v1.size() << ")\n"; const auto ret = std::ranges::remove(v1, ' '); std::cout << std::quoted(v1) << " (v1 nach `remove`, Größe: " << 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 nach `erase`, Größe: " << v1.size() << ")\n\n"; // remove_if mit benutzerdefiniertem unären Prädikat: auto rm = [](char c) { return !std::isupper(c); }; std::string v2{"Substitution Failure Is Not An Error"}; std::cout << std::quoted(v2) << " (v2, Größe: " << v2.size() << ")\n"; const auto [first, last] = std::ranges::remove_if(v2, rm); std::cout << std::quoted(v2) << " (v2 nach `remove_if`, Größe: " << v2.size() << ")\n"; std::cout << ' ' << std::string(std::distance(v2.begin(), first), '^') << '\n'; v2.erase(first, last); std::cout << std::quoted(v2) << " (v2 nach `erase`, Größe: " << v2.size() << ")\n\n"; // Erstellen einer Ansicht in einen Container, der durch `remove_if` modifiziert wird: for (std::string s : {"Small Object Optimization", "Non-Type Template Parameter"}) 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 wird abgeleitet #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}})); }
Mögliche Ausgabe:
"No _ Diagnostic _ Required" (v1, Größe: 26) "No_Diagnostic_Requiredired" (v1 nach `remove`, Größe: 26) ^^^^^^^^^^^^^^^^^^^^^^ "No_Diagnostic_Required" (v1 nach `erase`, Größe: 22) "Substitution Failure Is Not An Error" (v2, Größe: 36) "SFINAEtution Failure Is Not An Error" (v2 nach `remove_if`, Größe: 36) ^^^^^^ "SFINAE" (v2 nach `erase`, Größe: 6) "Small Object Optimization" => SOO "Non-Type Template Parameter" => NTTP
Siehe auch
|
(C++20)
(C++20)
|
kopiert einen Bereich von Elementen unter Auslassung derjenigen, die bestimmte Kriterien erfüllen
(Algorithmus-Funktionsobjekt) |
|
(C++20)
|
entfernt aufeinanderfolgende doppelte Elemente in einem Bereich
(Algorithmus-Funktionsobjekt) |
|
entfernt Elemente, die bestimmte Kriterien erfüllen
(Funktions-Template) |