EMZETT.
Login

Kurz: Ab C++11 hat sich die Sprache stark verändert. Diese Kapitel zeigen, was heute zum “modernen C++” gehört.

Teil des Kurses C++

Kapitel 13 von 15 im Kurs C++ (Abschnitt „Modernes C++“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Ab C++11 hat sich die Sprache stark verändert. Diese Kapitel zeigen, was heute zum “modernen C++” gehört.

Ranges (C++20)

Mit <ranges> kombinierst du Bearbeitungsschritte wie in einer Pipeline, lazy und ohne Zwischenkopien:

#include <iostream>
#include <vector>
#include <ranges>
#include <algorithm>
 
int main() {
    std::vector<int> zahlen{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
 
    auto ergebnis = zahlen
        | std::views::filter([](int x) { return x % 2 == 0; })      // nur gerade
        | std::views::transform([](int x) { return x * x; })        // quadrieren
        | std::views::take(3);                                       // die ersten drei
    for (int x : ergebnis) std::cout << x << ' ';
    std::cout << '\n';
 
    for (int i : std::views::iota(1, 6)) std::cout << i << ' ';      // 1 bis 5
    std::cout << '\n';
    for (int x : zahlen | std::views::reverse | std::views::drop(7)) std::cout << x << ' ';
    std::cout << '\n';
 
    std::ranges::sort(zahlen, std::greater<>{});                     // Algorithmus direkt auf dem Container
    std::cout << zahlen.front() << ' ' << std::ranges::count(zahlen, 5) << '\n';
    return 0;
}

Ausgabe:

4 16 36
1 2 3 4 5
3 2 1
10 1

Structured Bindings und Tupel

#include <iostream>
#include <tuple>
#include <map>
#include <string>
 
std::tuple<int, double, std::string> daten() { return {1, 2.5, "text"}; }
 
int main() {
    auto [i, d, s] = daten();
    std::cout << i << ' ' << d << ' ' << s << '\n';
    std::map<std::string, int> m{{"a", 1}, {"b", 2}};
    for (const auto& [k, v] : m) std::cout << k << v << ' ';
    std::cout << '\n';
    std::pair<std::string, int> p{"Mia", 17};
    auto& [name, alter] = p;
    alter++;
    std::cout << p.second << '\n';
    return 0;
}

Ausgabe:

1 2.5 text
a1 b2
18

Konstante Ausdrücke: constexpr und consteval

Funktionen und Objekte, die der Compiler schon beim Übersetzen auswertet:

#include <iostream>
#include <array>
 
constexpr bool istPrim(int n) {
    if (n < 2) return false;
    for (int i = 2; i * i <= n; i++) if (n % i == 0) return false;
    return true;
}
 
consteval int quadrat(int x) { return x * x; }                  // MUSS zur Übersetzungszeit laufen
 
template <int N>
constexpr auto primzahlen() {
    std::array<int, N> a{};
    int gefunden = 0;
    for (int k = 2; gefunden < N; k++) if (istPrim(k)) a[gefunden++] = k;
    return a;
}
 
int main() {
    constexpr auto p = primzahlen<8>();                          // komplett vom Compiler berechnet
    for (int x : p) std::cout << x << ' ';
    std::cout << '\n' << quadrat(12) << '\n';
    static_assert(istPrim(97));
    return 0;
}

Ausgabe:

2 3 5 7 11 13 17 19
144

Weitere nützliche Sprachmittel

MittelWirkung
auto, decltypeTypen ableiten
nullptrNullzeiger (statt NULL/0)
enum classtypsichere Aufzählung
using Name = Typ;Typalias (statt typedef)
= default, = deleteSpezialfunktionen anfordern/verbieten
override, finalÜberschreiben prüfen / verbieten
[[nodiscard]]Rückgabewert darf nicht ignoriert werden
std::span<T> (C++20)Sicht auf zusammenhängende Daten (Array, Vektor)
std::string_viewSicht auf Text
<=> (Spaceship)alle Vergleiche auf einmal
#include <iostream>
#include <span>
#include <vector>
#include <array>
#include <compare>
#include <string>
 
enum class Farbe { Rot, Gruen, Blau };                          // eigener Namensraum, kein Umwandeln in int
 
std::string name(Farbe f) {
    switch (f) { case Farbe::Rot: return "rot"; case Farbe::Gruen: return "grün"; case Farbe::Blau: return "blau"; }
    return "?";
}
 
double mittel(std::span<const double> werte) {                  // nimmt Array, vector, std::array ...
    double s = 0;
    for (double w : werte) s += w;
    return werte.empty() ? 0 : s / werte.size();
}
 
struct Version {
    int major, minor;
    auto operator<=>(const Version&) const = default;          // erzeugt <, >, <=, >=, ==, !=
};
 
int main() {
    std::cout << name(Farbe::Gruen) << '\n';
    std::vector<double> v{1, 2, 3, 4};
    double a[] = {10, 20};
    std::array<double, 3> arr{1, 1, 4};
    std::cout << mittel(v) << ' ' << mittel(a) << ' ' << mittel(arr) << '\n';
    std::cout << (Version{1, 2} < Version{1, 10}) << (Version{2, 0} == Version{2, 0}) << '\n';
    int* p = nullptr;
    std::cout << (p == nullptr) << '\n';
    return 0;
}

Ausgabe:

grün
2.5 15 2
11
1

Zeit und Zufall

#include <iostream>
#include <chrono>
#include <random>
#include <thread>
 
int main() {
    using namespace std::chrono;
    auto start = steady_clock::now();
    std::this_thread::sleep_for(20ms);
    auto dauer = duration_cast<milliseconds>(steady_clock::now() - start);
    std::cout << (dauer.count() >= 20) << '\n';
 
    std::mt19937 zufall(42);                                   // fester Startwert: reproduzierbar
    std::uniform_int_distribution<int> wuerfel(1, 6);
    for (int i = 0; i < 5; i++) std::cout << wuerfel(zufall) << ' ';
    std::cout << '\n';
    return 0;
}

Ausgabe:

1
3 5 6 2 5

Benutze <random> statt rand(): Es ist besser verteilt und thread-sicher nutzbar. Für Sicherheit (Schlüssel) nimmst du std::random_device oder Betriebssystem-Funktionen.

Module (C++20)

Module (import std;, export module ...;) ersetzen #include und Header: schneller übersetzbar, ohne Makro-Lecks. Die Unterstützung in Werkzeugen (CMake, Compiler) reift noch; neue Projekte können sie bereits ausprobieren. Dieser Kurs bleibt bei Headern, die überall funktionieren.

Merke

  • Ranges verketten filter, transform, take zu lazy Pipelines
  • Structured Bindings zerlegen Tupel, Paare, Maps und Strukturen
  • constexpr/consteval rechnen beim Übersetzen; static_assert prüft dort
  • enum class, nullptr, span, string_view, <=> machen Code sicherer und kürzer
  • <chrono> und <random> ersetzen time() und rand()

Übungsaufgabe

Nutze eine Ranges-Pipeline, um aus den Zahlen 1 bis 50 die Quadrate aller durch 3 teilbaren Zahlen zu bilden und die ersten fünf auszugeben.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Nebenläufigkeit: Threads, Mutex und Futures

Weiter: Projektaufbau, Tests und gute Praxis

Alle Kapitel: C++ im Überblick