namespace cpp

C++ lernen, kennen, anwenden

Benutzer-Werkzeuge

Webseiten-Werkzeuge


kennen:include:ranges

Inhaltsverzeichnis

<ranges>

Bereiche (ab C++20) 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 << ' ';
}

Fabriken

erzeugen Bereiche.

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 mit Werten, endet vor end
ranges::istream_view<T>(istream) liest Werte vom Typ T aus dem Eingabestrom istream
istream_view.cpp
#include <iostream>
#include <ranges>
#include <string>
#include <sstream>
 
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
common erzeugt Bereich, bei dem begin(r) und end(r) den selben Typ haben
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
filter(pred) gibt nur die Elemente weiter, für die pred(e) erfüllt ist
reverse kehrt Reihenfolge der Elemente um
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
join wandelt einen Bereich von Bereichen in einen "flachen" Bereich um
split(delim) erzeugt einen Bereich von Teilbereichen, delim kann einzelnes Element oder eine Folge sein
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>)

Beispiele

views_examples.cpp
#include <ranges>
#include <iostream>
#include <map>
#include <string>
#include <vector>
 
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.txt · Zuletzt geändert: 2020-07-08 18:10 von rrichter