namespace cpp {}

C++ lernen, kennen, anwenden

Benutzer-Werkzeuge

Webseiten-Werkzeuge


kennen:include:ranges

Dies ist eine alte Version des Dokuments!


<ranges>

Bereiche sind Elementfolgen, auf die begin(r) und end(r) anwendbar sind. Im Namensraum std::ranges::views oder kurz std::views definierte Sichten auf Bereiche lassen sich über Pipes | aneinander koppeln. Sie liefern die Werte eines Bereiches einzeln auf Anforderung.

views_pipelines.cpp
#include <iostream>
#include <ranges>
 
int main()
{
    using namespace std::views;
 
    auto output = 
          iota(1)
        | filter([](int x){ return x%2 == 0; })
        | transform([](int x){ return 3*x; })
        | take(10);
 
    // no calculation is done up to here (lazy evaluation)
 
    for (auto e : output) std::cout << 	e << ' ';
}

Anfang und Ende eines Views müssen nicht denselben Typ besitzen. Werden Iteratoren des selben Typs benötigt, können diese mit std::views::common erzeugt werden:

views_common.cpp
#include <iostream>
#include <ranges>
#include <vector>
 
int main()
{
    using namespace std::views;
 
    auto numbers = iota(1, 10) | common;
    auto v = std::vector<int>{numbers.begin(), numbers.end()};
 
    for (auto e : v) std::cout << e << ' ';
}

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.

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; 
}

Fabriken

erzeugen Bereiche (° : definiert in C++20, ³ : C++23):

empty leerer Bereich °
single(value) Bereich mit nur einem Wert °
iota(start) (unendlicher) Bereich mit Werten beginnend bei start, zählt mit ++ hoch °
iota(start, end) Zählbereich endet vor end °
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 ³
istream_view.cpp
#include <iostream>
#include <ranges>
#include <sstream>
#include <string>
 
int main()
{
    auto input = std::istringstream{"0 1 2 3 4 5 6 7 8 9"};
    auto below_5 = std::ranges::istream_view<int>(input) 
        | std::views::take_while([](auto x) { return x < 5; });	
 
    for (auto e : below_5) std::cout << e << ' ';
}

Sichten

übernehmen einen Bereich, verarbeiten dessen Elemente e und geben sie weiter.

all gibt alle Elemente weiter °
adjacent<N> erzeugt Tupel aus N benachbarten Elementen ³
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_rvalue erspart Kopieren: Elemente können per "move" übernommen werden ³
common erzeugt Bereich, bei dem begin(r) und end(r) den selben Typ haben °
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_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 °
drop(n) überspringt die ersten n Elemente °
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 ³
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_transform(f) adjacent_transform<2>(f) ³
reverse kehrt Reihenfolge der Elemente um °
slide(n) erzeugt einen gleitenden Fensterbereich aus n Elementen ³
stride(n) springt immer 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 °
transform(f) wendet f auf jedes Element e an, gibt f(e) weiter °
split(delim) erzeugt einen Bereich von Teilbereichen, delim kann einzelnes Element oder eine Folge sein °
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 ³

Beispiele

views_examples.cpp
#include <ranges>
#include <iostream>
#include <map>
#include <string>
#include <vector>
 
// waiting for P2286 Formatting Ranges ...
 
template <typename Range, typename Msg>
void show(Range&& r, Msg message)
{
    std::cout.width(30);
    std::cout << std::left << message <<  " : [";
    int cnt = 0;    
    for (auto&& e : r) 
    {
        std::cout << (cnt++ ? ",":"");
        std::cout << e;    
    }    
    std::cout << "]\n";
}
 
template <typename Range, typename Msg>
void show_range_of_ranges(Range&& r, Msg message)
{
    std::cout.width(30);
    std::cout << std::left << message << " : [";
    int cnt = 0;    
    for (auto&& inner_range : r) 
    {
        std::cout << (cnt++ ? ",":"") << "[";
        int inner_cnt = 0;    
        for (auto&& e : inner_range) 
        {
            std::cout << (inner_cnt++ ? ",":"");
            std::cout << e;    
        }
        std::cout << "]";        
    }    
    std::cout << "]\n";
}
 
int main()
{
    using namespace std::views;
 
    auto v = std::vector{0,1,2,3,4,5};
    auto s = std::string{"AB CD E"};
    auto m = std::map<std::string,int>{{"wrong", 6*9}, {"answer", 42}};
 
    show( empty<int>, "empty<T>");
    show( single(42), "single(42)");
    show( iota(0,6), "iota(0,6)");
    show( iota(0) | take(3), "iota(0) | take(3)");
    show( counted(begin(v), 3), "counted(begin(v),3)");
    show( v | all, "v | all");
    show( v | reverse, "v | reverse");
    show( v | take_while([](int x){ return x < 3; }), "v | take_while(below_3)");
    show( v | drop_while([](int x){ return x < 3; }), "v | drop_while(below_3)");
    show( v | filter([](int x){ return x%2 != 0; }), "v | filter(odd)");
    show( v | transform([](int x){ return x*x; }), "v | transform(square)");
 
    show( s , "s");
    show_range_of_ranges( s | split(' '), "s | split(\' \')");
    show( s | split(' ') | join, "s | split(\' \') | join");
 
    show( m | keys , "m | keys");
    show( m | values , "m | values");
}

erzeugt die Ausgabe

empty<T>                       : []
single(42)                     : [42]
iota(0,6)                      : [0,1,2,3,4,5]
iota(0) | take(3)              : [0,1,2]
counted(begin(v),3)            : [0,1,2]
v | all                        : [0,1,2,3,4,5]
v | reverse                    : [5,4,3,2,1,0]
v | take_while(below_3)        : [0,1,2]
v | drop_while(below_3)        : [3,4,5]
v | filter(odd)                : [1,3,5]
v | transform(square)          : [0,1,4,9,16,25]
s                              : [A,B, ,C,D, ,E]
s | split(' ')                 : [[A,B],[C,D],[E]]
s | split(' ') | join          : [A,B,C,D,E]
m | keys                       : [answer,wrong]
m | values                     : [42,54]
kennen/include/ranges.1708345334.txt.gz · Zuletzt geändert: 2024-02-19 13:22 von rrichter

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki