zurück zum Artikel

C++20: Die Ranges-Bibliothek

Rainer Grimm

Dank der Ranges-Bibliothek in C++20 wird der Umgang mit der Standard Template Library deutlich angenehmer und mächtiger. Ihre Algorithmen sind lazy, agieren direkt auf den Containern und können verknüpft werden. Um es kurz zu machen: Die Bequemlichkeit und Mächtigkeit der Ranges-Bibliothek beruht auf ihren funktionalen Ideen.

Dank der Ranges-Bibliothek in C++20 wird der Umgang mit der Standard Template Library deutlich angenehmer und mächtiger. Ihre Algorithmen sind lazy, agieren direkt auf den Containern und können verknüpft werden. Um es kurz zu machen: Die Bequemlichkeit und Mächtigkeit der Ranges-Bibliothek beruht auf ihren funktionalen Ideen.

Bevor ich auf die Details eingehe, möchte ich ein erstes Beispiel zur Ranges-Bibliothek vorstellen:

// rangesFilterTransform.cpp

#include <iostream>
#include <ranges>
#include <vector>

int main() {

std::vector<int> numbers = {1, 2, 3, 4, 5, 6};

auto results = numbers | std::views::filter([](int n){ return n % 2 == 0; })
| std::views::transform([](int n){ return n * 2; });

for (auto v: results) std::cout << v << " "; // 4 8 12

}

Du musst den Ausdruck von links nach rechts lesen. Das Pipe-Symbol steht für die Verknüpfung von Funktionen: Zuerst werden alle Elemente akzeptiert, die gerade sind (std::views::filter([](int n){ return n % 2 == 0; })). Danach wird jedes verbleibende Element verdoppelt (std::views::transform([](int n){ return n * 2; })). Dieses kleine Beispiel zeigt bereits zwei neue Feature der Ranges-Bibliothek: zum einen die Funktionskomposition, und zum anderen agiert diese Funktionskomposition direkt auf dem Container.

Jetzt solltest du für die Details gewappnet sein. Damit sind wir wieder am Startpunkt angelangt: Ranges und Views sind Concepts.

C++20: Die Ranges Bibliothek

Es gibt einige Verfeinerungen von std::range:

C++20: Die Ranges Bibliothek

Die Container der STL und der std::string setzen verschiedene Concepts um: Ein Containter, der das Concept std::ranges::contiguous_range unterstützt, unterstützt auch alle vorherigen Concepts in der Tabelle wie std::ranges::random_access_range, std::ranges::bidirectional_range und std::ranges::input_range. Diese Beobachtung gilt natürlich auch für die anderen Ranges der Tabelle.

std::vector<int> numbers = {1, 2, 3, 4, 5, 6};

auto results = numbers | std::views::filter([](int n){ return n % 2 == 0; })
| std::views::transform([](int n){ return n * 2; });

In dem Codebeispiel ist numbers die Range, während std::views::filter und std::views::transform für die Views stehen.

Dank der Mächtigkeit der Views erlaubt die Ranges-Bibliothek das Programmieren im funktionalen Stil. Views lassen sich verknüpfen und sind lazy. Ich habe bereits zwei Views vorgestellt. Natürlich enthält C++20 deutlich mehr:

std::all_view, std::views::all // takes all elements

std::ref_view // takes all elements of another view

std::filter_view, std::views::filter // takes the elements which satisfies the predicate

std::transform_view, std::views::transform // transforms each element

std::take_view, std::views::take // takes the first N elements of another view

std::take_while_view, std::views::take_while // takes the elements of another view as long as the predicate returns true

std::drop_view, std::views::drop // skips the first N elements of another view

std::drop_while_view, std::views::drop_while // skips the initial elements of another view until the predicate returns false

std::join_view, std::views::join // joins a view of ranges

std::split_view, std::views::split // splits a view by using a delimiter

std::common_view, std::views::common // converts a view into a std::common_range

std::reverse_view, std::views::reverse // iterates in reverse order

std::basic_istream_view, std::istream_view // applies operator>> on the view

std::elements_view, std::views::elements // creates a view on the N-th element of tuples

std::keys_view, std::views::keys // creates a view on the first element of a pair-like values

std::values_view, std::views::values // creates a view on the second elements of a pair-like values

Im Allgemeinen lässt sich ein View wie std::views::transform mit dem alternativen Namen std::transform_view verwenden. Bei meiner weiteren Vorstellung der Ranges-Bibliothek werde ich die Views anwenden.

Soweit ich weiß, gibt es zum jetzigen Zeitpunkt (Februar 2020) keine Implementierung der Ranges-Bibliothek. Das ist aber kein Problem, da die bereits erwähnte ranges-v3 [2]-Implementierung verfügbar ist. Am einfachsten ist es, den Online-Compiler Wandbox [3] oder den Compiler Explorer [4] mit dem HEAD GCC zu verwenden. Dazu müssen meine Beispiele wie rangesFilterExample.cpp leicht modifiziert werden:

C++20: Die Ranges Bibliothek

Wende ich die Transformationsschritte auf das Programm rangesFilterTransform.cpp an, erhalte ich das folgende Programm:

// rangesV3FilterTransform.cpp

#include <iostream>
#include <range/v3/all.hpp>
#include <vector>

int main() {

std::vector<int> numbers = {1, 2, 3, 4, 5, 6};

auto results = numbers | ranges::views::filter([](int n){ return n % 2 == 0; })
| ranges::views::transform([](int n){ return n * 2; });

for (auto v: results) std::cout << v << " ";

}

Dank der Wandbox [7] muss ich dieses Mal die Ausgabe nicht vortäuschen.

C++20: Die Ranges Bibliothek

In diesem Artikel ging ich auf die Grundlagen zur Ranges-Bibliothek ein. Dank ihnen kann ich mich in meinem nächsten Artikel auf die Mächtigkeit der Ranges fokussieren. Die Ranges-Bibliothek erweitert C++20 mit zwei neuen Konzepten: Funktionskomposition und Lazy Evaluation. Diese Erweiterung ist genau der Grund dafür, dass die Ranges-Bibliothek zu den großen Vier in C++20 [8] gezählt werden muss. Jede ihrer Komponenten ändert die Art und Weise, wie wir C++ verwenden werden. ( [9])


URL dieses Artikels:
https://www.heise.de/-4661566

Links in diesem Artikel:
[1] https://github.com/ericniebler/range-v3
[2] https://github.com/ericniebler/range-v3
[3] https://wandbox.org/
[4] https://godbolt.org/
[5] https://github.com/ericniebler/range-v3
[6] https://github.com/ericniebler/range-v3
[7] https://wandbox.org/
[8] https://heise.de/-4568956
[9] mailto:rainer@grimm-jaud.de