Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende ÜberarbeitungNächste ÜberarbeitungBeide Seiten der Revision |
kennen:include:ranges [2024-02-11 17:27] – [Sichten] rrichter | kennen:include:ranges [2024-02-20 15:25] – rrichter |
---|
====== <ranges> ====== | ====== <ranges> ====== |
Bereiche (ab [[..:begriffe#C++20]]) sind Elementfolgen, auf die ''%%begin(r)%%'' und ''%%end(r)%%'' anwendbar sind. | Bereiche sind Elementfolgen, auf die ''%%begin(r)%%'' und ''%%end(r)%%'' anwendbar sind. |
| Die Algorithmen der Standardbibliothek erlauben seit [[..:begriffe#C++20]] die Schreibweise ''std::ranges::sort(v)'' statt ''std::sort(begin(v), end(v))''. |
| Allerdings sind die einzelnen Algorithmen jeweils nacheinander auszuführen, also nicht koppelbar. |
| MIt einem anderen Ansatz soll dieser Nachteil behoben werden. |
Im Namensraum ''std::ranges::views'' oder kurz ''std::views'' | Im Namensraum ''std::ranges::views'' oder kurz ''std::views'' |
definierte Sichten auf Bereiche lassen sich über Pipes ''|'' aneinander koppeln. | definierte Sichten auf Bereiche lassen sich über Pipes ''|'' aneinander koppeln. |
Sie liefern die Werte eines Bereiches einzeln auf Anforderung. | Sie liefern die Werte eines Bereiches einzeln auf Anforderung, also über [[https://de.wikipedia.org/wiki/Lazy_Evaluation|lazy evaluation]]. |
| |
<code cpp views_pipelines.cpp> | <code cpp views_pipelines.cpp> |
| |
for (auto e : v) std::cout << e << ' '; | for (auto e : v) std::cout << e << ' '; |
| } |
| </code> |
| ===== Quellen und Senken ===== |
| Sequentielle und assoziative (!) Container können als Quellbereiche dienen. Mit ''ranges::to<Container>()'' (C++23) wird ein neuer Container als Senke für die verarbeiteten Daten erzeugt. Der Elementtyp wird automatisch bestimmt. |
| |
| <code cpp to.cpp> |
| #include <iostream> |
| #include <ranges> |
| #include <set> |
| #include <vector> |
| |
| int main() |
| { |
| std::set s{ 'h', 'a', 'l', 'o' }; |
| auto v = s | std::views::take(2) | std::ranges::to<std::vector>(); |
| for (auto e : v) std::cout << e; |
} | } |
</code> | </code> |
| |
===== Fabriken ===== | ===== Fabriken ===== |
erzeugen Bereiche. | erzeugen Bereiche (° : definiert in [[..:begriffe#C++20]], ³ : [[..:begriffe#C++23]]): |
| |
| ''empty'' | leerer Bereich | | | ''empty'' | leerer Bereich | ° | |
| ''single(value)''| Bereich mit nur einem Wert | | | ''single(value)''| Bereich mit nur einem Wert | ° | |
| ''iota(start)''| (unendlicher) Bereich mit Werten beginnend bei ''start'', zählt mit ''++'' hoch | | | ''iota(start)''| (unendlicher) Bereich mit Werten beginnend bei ''start'', zählt mit ''++'' hoch | ° | |
| ''iota(start, end)''| Zählbereich mit Werten, endet vor ''end'' | | | ''iota(start, end)''| Zählbereich endet vor ''end'' | ° | |
| ''ranges::istream_view<T>(istream)'' | liest Werte vom Typ ''T'' aus dem Eingabestrom ''istream'' | | | ''ranges::istream_view<T>(istream)'' | liest Werte vom Typ ''T'' aus dem Eingabestrom ''istream'' | ° | |
| | ''repeat(value)'' | wiederholt den Wert unbegrenzt oft | ³ | |
| | ''repeat(value, n)'' | liefert den Wert genau ''n'' Mal | ³ | |
| |
<code cpp istream_view.cpp> | <code cpp istream_view.cpp> |
#include <iostream> | #include <iostream> |
#include <ranges> | #include <ranges> |
#include <string> | |
#include <sstream> | #include <sstream> |
| #include <string> |
| |
int main() | int main() |
{ | { |
auto input = std::istringstream{"0 1 2 3 4 5 6 7 8 9"}; | auto input = std::istringstream{"0 1 2 3 4 5 6 7 8 9"}; |
auto below_5 = std::ranges::istream_view<int>(input) | auto below_5 = std::ranges::istream_view<int>(input) |
| std::views::take_while([](auto x) { return x < 5; }); | | std::views::take_while([](auto x) { return x < 5; }); |
| |
for (auto e : below_5) std::cout << e << ' '; | for (auto e : below_5) std::cout << e << ' '; |
} | } |
</code> | </code> |
| |
===== Sichten ===== | ===== Sichten ===== |
übernehmen einen Bereich, verarbeiten dessen Elemente ''e'' und geben sie weiter. | übernehmen einen oder mehrere Bereiche, verarbeiten dessen / deren Elemente ''e'' und geben sie weiter. |
| |
^ ^ ^ seit* ^ | |
| ''all'' | gibt alle Elemente weiter | ° | | | ''all'' | gibt alle Elemente weiter | ° | |
| ''adjacent<N>'' | erzeugt Tuple aus N benachbarten Elementen | ³ | | | ''adjacent<N>'' | erzeugt Tupel aus ''N'' benachbarten Elementen | ³ | |
| ''adjacent[_transform(f)'' | wendet ''f'' auf die erzeugten Tupel an | ³ | | | ''adjacent_transform<N>(f)'' | wendet ''f(e1,e2,...)'' auf ''N'' benachbarte Elemente ''e1,e2,...'' an | ³ | |
| ''as_const'' | Elemente dürfen nicht verändert werden | ³ | | | ''as_const'' | Elemente dürfen nicht verändert werden | ³ | |
| ''as_rvalue'' | erspart Kopieren: Elemente können per "move" übernommen werden | ³ | | | ''as_rvalue'' | erspart Kopieren: Elemente können per "move" übernommen werden | ³ | |
| ''common'' | erzeugt Bereich, bei dem ''%%begin(r)%%'' und ''%%end(r)%%'' den selben Typ haben | ° | | | ''common'' | erzeugt Bereich, bei dem ''%%begin(r)%%'' und ''%%end(r)%%'' den selben Typ haben | ° | |
| ''cartesian_product(rg1,rg2,...)'' | bildet Tupel aus jedem mit jedem aus 2 oder mehr gegebenen Bereichen | ³ | | | ''cartesian_product(rg1,rg2,...)'' | bildet die Kreuzmenge, d.h. alle Tupel aus jedem mit jedem aus 2 oder mehr gegebenen Bereichen | ³ | |
| ''chunk(n)'' | unterteilt in Teilbereiche aus n aufeinander folgenden Elementen | ³ | | | ''chunk(n)'' | unterteilt in Teilbereiche aus ''n'' aufeinander folgenden Elementen | ³ | |
| ''chunk_by(pred)'' | aufeinander folgende Elemente a,b gehören zum gleichen Teilbereich, wenn ''pred(a,b)'' wahr ist | ³ | | | ''chunk_by(pred)'' | aufeinander folgende Elemente ''a'',''b'' gehören zum gleichen Teilbereich, wenn ''pred(a,b)'' wahr ist | ³ | |
| ''counted(iter, n)'' | liefert ''n'' Werte, beginnend mit Iterator ''iter'' | ° | | | ''counted(iter, n)'' | liefert ''n'' Werte, beginnend mit Iterator ''iter'' | ° | |
| ''drop(n)'' | überspringt die ersten ''n'' Elemente | ° | | | ''drop(n)'' | überspringt die ersten ''n'' Elemente | ° | |
| ''drop_while(pred)'' | überspringt Elemente, solange ''pred(e)'' erfüllt ist | ° | | | ''drop_while(pred)'' | überspringt Elemente, solange ''pred(e)'' erfüllt ist | ° | |
| | ''elements<N>'' | gibt den ''N''-ten Bestandteil von tupelartigen Elementen weiter | ° | |
| ''enumerate'' | erzeugt Index-Wert-Paare | ³ | | | ''enumerate'' | erzeugt Index-Wert-Paare | ³ | |
| ''filter(pred)'' | gibt nur die Elemente weiter, für die ''pred(e)'' erfüllt ist | ° | | | ''filter(pred)'' | gibt nur die Elemente weiter, für die ''pred(e)'' erfüllt ist | ° | |
| | ''join'' | wandelt einen Bereich von Bereichen in einen "flachen" Bereich um | ° | |
| | ''join_with(pattern)'' | verbindet Teilbereiche und fügt ''pattern'' dazwischen ein | ³ | |
| | ''keys'' | gibt alle Schlüssel von Schlüssel-Wert-Paaren weiter (''elements<0>'') | ° | |
| ''pairwise'' | ''adjacent<2>'' | ³ | | | ''pairwise'' | ''adjacent<2>'' | ³ | |
| ''pairwise_transform(f)'' | ''adjacent_tansform(f)'' | ³ | | | ''pairwise_transform(f)'' | ''adjacent_transform<2>(f)'' | ³ | |
| ''repeat(x,n)'' | wiederholt x n Mal oder immer wieder, falls n fehlt | ³ | | |
| ''reverse'' | kehrt Reihenfolge der Elemente um | ° | | | ''reverse'' | kehrt Reihenfolge der Elemente um | ° | |
| ''slide(n)'' | erzeugt ein gleitendes Fenster aus n Elementen | ³ | | | ''slide(n)'' | erzeugt einen gleitenden Fensterbereich aus n Elementen | ³ | |
| ''stride(n)'' | springt immer n Elemente weiter | ³ | | | ''stride(n)'' | springt immer n Elemente weiter | ³ | |
| ''take(n)'' | gibt nur die ersten ''n'' Elemente weiter | ° | | | ''take(n)'' | gibt nur die ersten ''n'' Elemente weiter | ° | |
| ''take_while(pred)'' | gibt Elemente nur solange weiter, wie ''pred(e)'' erfüllt ist | ° | | | ''take_while(pred)'' | gibt Elemente nur solange weiter, wie ''pred(e)'' erfüllt ist | ° | |
| ''transform(f)'' | wendet ''f'' auf jedes Element ''e'' an, gibt ''f(e)'' weiter | ° | | | ''transform(f)'' | wendet ''f'' auf jedes Element ''e'' an, gibt ''f(e)'' weiter | ° | |
| | | | | |
| ''join'' | wandelt einen Bereich von Bereichen in einen "flachen" Bereich um | ° | | |
| ''join_with(pattern)'' | verbindet Teilbereiche und fügt ''pattern'' dazwischen ein | ³ | | |
| ''split(delim)'' | erzeugt einen Bereich von Teilbereichen, ''delim'' kann einzelnes Element oder eine Folge sein | ° | | | ''split(delim)'' | erzeugt einen Bereich von Teilbereichen, ''delim'' kann einzelnes Element oder eine Folge sein | ° | |
| ''zip(rg1,rg2,...)'' | erzeugt Tupel aus zwei oder mehr Bereichen | ³ | | |
| ''zip_transform(f)'' | wendet ''f'' auf die erzeugten Tupel an | ³ | | |
| | | | | |
| ''elements<N>'' | gibt den ''N''-ten Bestandteil von tupelartigen Elementen weiter | ° | | |
| ''keys'' | gibt alle Schlüssel von Schlüssel-Wert-Paaren weiter (''elements<0>'') | ° | | |
| ''values'' | gibt alle Werte von Schlüssel-Wert-Paaren weiter (''elements<1>'') | ° | | | ''values'' | gibt alle Werte von Schlüssel-Wert-Paaren weiter (''elements<1>'') | ° | |
| | | | | | ''zip(rg1,rg2,...)'' | erzeugt Tupel aus zwei oder mehr Bereichen | ³ | |
| | ''zip_transform(f,rg1,rg2,...)'' | ruft ''f(e1,e2,...)'' mit Argumenten ''e1,e2,...'' aus gegebenen Bereichen auf | ³ | |
| |
° : seit C++20, ³ : seit C++23 | |
| |
===== Beispiele ===== | ===== Beispiele ===== |
#include <string> | #include <string> |
#include <vector> | #include <vector> |
| |
| // waiting for P2286 Formatting Ranges ... |
| |
template <typename Range, typename Msg> | template <typename Range, typename Msg> |