Modernes C++ programmieren

Okt 23, 2024

cpp23-listings-README-onepage.md

Listings of Gesamt.docx

This is the list of listings on one page. You can also view a linked summary.

Listing 1.1: Ein kleines Formatbeispiel

Book listing lst-0001-book.cpp:

// https://godbolt.org/z/jrqEGvh1M 
#include <iostream>              // cout
#include <memory>                // make_shared
int main() {                     // ein Kommentar
  std::cout << "Blopp\n";        // hervorgehoben
  Typ feh-ler(args);             //             (ERR)  Zeile mit einem Fehler
  if consteval {                 // auf C++23-Features weise ich hin
      sin(55); }
  for(;;) break; // andere Markierung, zur Unterscheidung oder Hervorhebung
}

Godbolt Listing lst-0001-godb.cpp, https://godbolt.org/z/jrqEGvh1M:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jrqEGvh1M 
#include <iostream>              // cout
#include <memory>                // make_shared
int main() {                     // ein Kommentar
  std::cout << "Blopp\n";        // hervorgehoben
  Typ feh-ler(args);             //             (ERR)  Zeile mit einem Fehler
  if consteval {                 // auf C++23-Features weise ich hin
      sin(55); }
  for(;;) break; // andere Markierung, zur Unterscheidung oder Hervorhebung
}

Listing 2.1: Jede Fibonacci-Zahl ist die Summe der beiden Zahlen davor.

Book listing lst-0002-book.cpp:

// https://godbolt.org/z/aEvcPWzn5 
// modern101.cpp : Fibonacci-Konsole
#include <iostream>
int fib(int n) {
    return n<=1 ? n : fib(n-2) + fib(n-1);
}
int main() {
    std::cout << "Die wievielte Fibonacci-Zahl? ";
    int n = 0;
    std::cin >> n;
    std::cout << "fib(" << n << ")=" << fib(n) << "\n";
}

Godbolt Listing lst-0002-godb.cpp, https://godbolt.org/z/aEvcPWzn5:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/aEvcPWzn5 
// modern101.cpp : Fibonacci-Konsole
#include <iostream>
int fib(int n) {
    return n<=1 ? n : fib(n-2) + fib(n-1);
}
int main() {
    std::cout << "Die wievielte Fibonacci-Zahl? ";
    int n = 0;
    std::cin >> n;
    std::cout << "fib(" << n << ")=" << fib(n) << "\n";
}

Listing 2.2: Eine zügig erstellte Tabelle von Fibonacci-Zahlen

Book listing lst-0003-book.cpp:

// https://godbolt.org/z/Tbx6qdrfx 
// modern102.cpp : Fibonacci-Konsole
#include <iostream>
#include <map>
int fib(int n) {
    static std::map<int, int> table{};
    table[n] = n<=1 ? n : table[n-2] + table[n-1];
    return table[n];
}
int main() {
    std::cout << "Wie viele Fibonacci-Zahlen? ";
    int n = 0;
    std::cin >> n;
    for (int i = 1; i <= n; ++i)
        std::cout << "fib(" << i << ")=" << fib(i) << "\n";
}

Godbolt Listing lst-0003-godb.cpp, https://godbolt.org/z/Tbx6qdrfx:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Tbx6qdrfx 
// modern102.cpp : Fibonacci-Konsole
#include <iostream>
#include <map>
int fib(int n) {
    static std::map<int, int> table{};
    table[n] = n<=1 ? n : table[n-2] + table[n-1];
    return table[n];
}
int main() {
    std::cout << "Wie viele Fibonacci-Zahlen? ";
    int n = 0;
    std::cin >> n;
    for (int i = 1; i <= n; ++i)
        std::cout << "fib(" << i << ")=" << fib(i) << "\n";
}

Listing 3.2: (C++) In C++ hat man statt Referenzen erst einmal Werte.

Book listing lst-0004-book.cpp:

Data data{5};
Data mehr{6};
data = mehr;
mehr.value = 7;
cout << data.value << '\n'; // immer noch 6

Listing 3.3: (C++) Modernes C++ mit Heapspeicher nutzt Hilfsklassen wie shared_ptr.

Book listing lst-0005-book.cpp:

// https://godbolt.org/z/WM11Gs6sz 
auto data = make_shared<Data>(5);
auto mehr = make_shared<Data>(6);
data = mehr;
mehr->value = 7;
cout << data->value << '\n'; // jetzt auch 7

Godbolt Listing lst-0005-godb.cpp, https://godbolt.org/z/WM11Gs6sz:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WM11Gs6sz 
auto data = make_shared<Data>(5);
auto mehr = make_shared<Data>(6);
data = mehr;
mehr->value = 7;
cout << data->value << '\n'; // jetzt auch 7

Listing 3.4: (C++) Ohne moderne C++-Mittel muss man besonders auf den Zeigerbesitz achten.

Book listing lst-0006-book.cpp:

// https://godbolt.org/z/Ee7eqq1MY 
Data* dataOwner = new Data(5);
Data* data = dataOwner;
Data* mehr = new Data(6);
data = mehr;
mehr->value = 7;
cout << data->value << '\n'; // jetzt auch 7
/* selbst wegräumen */
delete mehr;
delete dataOwner;

Godbolt Listing lst-0006-godb.cpp, https://godbolt.org/z/Ee7eqq1MY:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Ee7eqq1MY 
Data* dataOwner = new Data(5);
Data* data = dataOwner;
Data* mehr = new Data(6);
data = mehr;
mehr->value = 7;
cout << data->value << '\n'; // jetzt auch 7
/* selbst wegräumen */
delete mehr;
delete dataOwner;

Listing 3.6: (C++) const kann den Wert oder die Referenz schützen.

Book listing lst-0007-book.cpp:

// https://godbolt.org/z/Moe5M7sK8 
Data const * data = new Data(5);
data->value = 7;         // dieses const schützt Data
data = new Data(6);      // Zeiger neu zuweisen ist okay
Data * const mehr = new Data(8);
mehr->value = 9;         // jetzt okay
mehr = new Data(10);     // Referenz ist geschützt

Godbolt Listing lst-0007-godb.cpp, https://godbolt.org/z/Moe5M7sK8:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Moe5M7sK8 
Data const * data = new Data(5);
data->value = 7;         // dieses const schützt Data
data = new Data(6);      // Zeiger neu zuweisen ist okay
Data * const mehr = new Data(8);
mehr->value = 9;         // jetzt okay
mehr = new Data(10);     // Referenz ist geschützt

Listing 4.7: Ein sehr einfaches C++-Programm

Book listing lst-0008-book.cpp:

// https://godbolt.org/z/Mdj7bGvar 
#include <iostream>                         // Module/Bibliotheken einbinden
int main()                                  // main() ist der Beginn des Programms
{
    int wert = 100;                         // Variable mit Anfangswert
    std::cout << "Teiler von " << wert << " sind:\n";    // Ausgabe von Text
    for(int teiler=1; teiler <= wert; teiler = teiler+1) // Schleife von 1 bis 100
    {                                       // hier beginnt der Wiederholungsteil
        if(wert % teiler == 0)              // Test für eine bedingte Ausführung
            std::cout << teiler << ", ";    // nur bei positivem Test
    }                                       // Ende der Schleife
    std::cout << "\n";                      // einmalige Ausgabe
    return 0;                               // bedeutet in main() Programmende
}                                           // Ende von main()

Godbolt Listing lst-0008-godb.cpp, https://godbolt.org/z/Mdj7bGvar:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Mdj7bGvar 
#include <iostream>                         // Module/Bibliotheken einbinden
int main()                                  // main() ist der Beginn des Programms
{
    int wert = 100;                         // Variable mit Anfangswert
    std::cout << "Teiler von " << wert << " sind:\n";    // Ausgabe von Text
    for(int teiler=1; teiler <= wert; teiler = teiler+1) // Schleife von 1 bis 100
    {                                       // hier beginnt der Wiederholungsteil
        if(wert % teiler == 0)              // Test für eine bedingte Ausführung
            std::cout << teiler << ", ";    // nur bei positivem Test
    }                                       // Ende der Schleife
    std::cout << "\n";                      // einmalige Ausgabe
    return 0;                               // bedeutet in main() Programmende
}                                           // Ende von main()

Listing 4.8: Dieses Programm fragt seine Benutzer nach einer Zahl.

Book listing lst-0016-book.cpp:

// https://godbolt.org/z/d7Yjr9jdb 
#include <iostream>    // für std::cin, std::cout, std::endl
#include <string>      // std::stoi

void berechne(int n) {                             // eine eigene Funktion
    using namespace std;                           // für std::cout und std::endl
    /* Teiler ausgeben */
    cout << "Teiler von " << n << " sind:\n";
    if(n == 0) { cout << "0\n"; return; }          // 0 ist Teiler von 0
    for(int teiler=1; teiler <= n; ++teiler) {     // statt teiler=teiler+1
        if(n % teiler == 0)
            cout << teiler << ", ";
    }
    cout << endl;
}
int main(int argc, const char* argv[]) {           // Argumente für main
    /* Zahl ermitteln */
    int wert = 0;
    if(argc<=1) {
        std::cout << "Geben Sie eine Zahl ein: ";
        std::cin >> wert;                          // in Variable wert lesen
        if(!std::cin) {                            // prüfen, ob lesen klappte
            return 1;                              // Fehler bei Benutzereingabe
        }
    } else {
        wert = std::stoi(argv[1]);
    }
    berechne(wert);                                // Funktionsaufruf
    return 0;
}

Godbolt Listing lst-0016-godb.cpp, https://godbolt.org/z/d7Yjr9jdb:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/d7Yjr9jdb 
#include <iostream>    // für std::cin, std::cout, std::endl
#include <string>      // std::stoi

void berechne(int n) {                             // eine eigene Funktion
    using namespace std;                           // für std::cout und std::endl
    /* Teiler ausgeben */
    cout << "Teiler von " << n << " sind:\n";
    if(n == 0) { cout << "0\n"; return; }          // 0 ist Teiler von 0
    for(int teiler=1; teiler <= n; ++teiler) {     // statt teiler=teiler+1
        if(n % teiler == 0)
            cout << teiler << ", ";
    }
    cout << endl;
}
int main(int argc, const char* argv[]) {           // Argumente für main
    /* Zahl ermitteln */
    int wert = 0;
    if(argc<=1) {
        std::cout << "Geben Sie eine Zahl ein: ";
        std::cin >> wert;                          // in Variable wert lesen
        if(!std::cin) {                            // prüfen, ob lesen klappte
            return 1;                              // Fehler bei Benutzereingabe
        }
    } else {
        wert = std::stoi(argv[1]);
    }
    berechne(wert);                                // Funktionsaufruf
    return 0;
}

Listing 4.9: Ein sehr außergewöhnlich formatiertes Stück Quellcode

Book listing lst-0017-book.cpp:

// https://godbolt.org/z/eWfGbv1dG 
#          include <iostream>        // # muss am Zeilenanfang stehen
int             main(
    ){
    std::cout
<<"Dies ist "
        "Text mit <Klammern>\n"   // String-Literal unterbrochen durch neue Zeile
        ;
    /*Typ:*/ int
    /*Variable:*/ ein_Wert
    /*Init:*/ = 100;               // innere Kommentare
std::cout<<ein_Wert<<"\n";}       // keine Leerzeichen

Godbolt Listing lst-0017-godb.cpp, https://godbolt.org/z/eWfGbv1dG:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eWfGbv1dG 
#          include <iostream>        // # muss am Zeilenanfang stehen
int             main(
    ){
    std::cout
<<"Dies ist "
        "Text mit <Klammern>\n"   // String-Literal unterbrochen durch neue Zeile
        ;
    /*Typ:*/ int
    /*Variable:*/ ein_Wert
    /*Init:*/ = 100;               // innere Kommentare
std::cout<<ein_Wert<<"\n";}       // keine Leerzeichen

Listing 4.10: Kommentare mit / und / können über mehrere Zeilen gehen oder eine Programmzeile auch unterbrechen.

Book listing lst-0018-book.cpp:

int main() {
    /* Mein erstes Programm. Es wurde
        geschrieben von Max Muster.*/
    return /* Die Null des Erfolgs */ 0;
}

Listing 4.11: Eine eigene C++-Funktion

Book listing lst-0021-book.cpp:

// https://godbolt.org/z/qWxq4KEKr 
void berechne(int n) {                           // eine eigene Funktion
    using namespace std;                         // für std::cout und std::endl
    /* Teiler ausgeben */
    cout << "Teiler von " << n << " sind:\n";
    for(int teiler=1; teiler <= n; ++teiler) {   // statt teiler=teiler+1
        if(n % teiler == 0)
            cout << teiler << ", ";
    }
    cout << endl;
}

Godbolt Listing lst-0021-godb.cpp, https://godbolt.org/z/qWxq4KEKr:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qWxq4KEKr 
void berechne(int n) {                           // eine eigene Funktion
    using namespace std;                         // für std::cout und std::endl
    /* Teiler ausgeben */
    cout << "Teiler von " << n << " sind:\n";
    for(int teiler=1; teiler <= n; ++teiler) {   // statt teiler=teiler+1
        if(n % teiler == 0)
            cout << teiler << ", ";
    }
    cout << endl;
}

Listing 4.12: Präfixoperatoren werden vor der Berechnung ausgeführt.

Book listing lst-0022-book.cpp:

// https://godbolt.org/z/4Mr6fnaEr 
#include <iostream> // cout
int main() {
    int basis = 2;
    int index = 10;
    int zahl = 3 * (basis + ++index) - 1;  // zuerst wird index erhöht
    std::cout << zahl << '\n';             // Ausgabe: 38
}

Godbolt Listing lst-0022-godb.cpp, https://godbolt.org/z/4Mr6fnaEr:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4Mr6fnaEr 
#include <iostream> // cout
int main() {
    int basis = 2;
    int index = 10;
    int zahl = 3 * (basis + ++index) - 1;  // zuerst wird index erhöht
    std::cout << zahl << '\n';             // Ausgabe: 38
}

GodboltId:r5hjrqqK9

Book listing lst-0024-book.cpp:

// https://godbolt.org/z/r5hjrqqK9 
#include <iostream>
int main() {
    int var = 10;
    var += 2;
    var *= 3;
    var /= 4;
    var -= 5;
    std::cout << var << "\n"; // ergibt 4
}

Godbolt Listing lst-0024-godb.cpp, https://godbolt.org/z/r5hjrqqK9:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/r5hjrqqK9 
#include <iostream>
int main() {
    int var = 10;
    var += 2;
    var *= 3;
    var /= 4;
    var -= 5;
    std::cout << var << "\n"; // ergibt 4
}

Listing 4.13: Ein Programm, das nur aus main und return besteht

Book listing lst-0025-book.cpp:

int main() {
    if(2 < 1) return 1;    // ein return
    return 0;              // anderes return
}                          // Ende von main

Listing 4.14: Hier setzen Sie nur die äußeren geschweiftenKlammern.

Book listing lst-0026-book.cpp:

for(int teiler=1; teiler <= n; ++teiler)  // for-Schleife
{                                         // Beginn des Schleifenblocks
    if(n % teiler == 0)
        std::cout << teiler << ", ";
}                                         // Ende des Schleifenblocks

Listing 4.15: So sieht es aus, wenn Sie alle geschweiften Klammern setzen.

Book listing lst-0027-book.cpp:

if(argc<=1) {                             // Beginn der if-Anweisung
    std::cout << "Geben Sie eine Zahl ein: ";
    std::cin >> zahl;
    if(!std::cin) {
        return 1;
    }
} else {
    wert = std::stoi(argv[1]);
}                                         // Ende der if-Anweisung

Listing 4.16: Das »if« ist eine Anweisung und benötigt eigentlich keine geschweiften Klammern.

Book listing lst-0028-book.cpp:

for(int teiler=1; teiler <= wert; ++teiler)
    if(wert % teiler == 0)
        std::cout << teiler << ", ";

Listing 4.17: Setzen Sie besser auch einzelne Anweisungen in geschweifte Klammern.

Book listing lst-0030-book.cpp:

for(int teiler=1; teiler <= wert; ++teiler) {
    if(wert % teiler == 0) {
        std::cout << teiler << ", ";
    }
}

Listing 4.18: Zuweisung des Ergebnisses eines Funktionsaufrufs

Book listing lst-0033-book.cpp:

wert = std::stoi(argv[1]);

Listing 4.19: Zuweisung des Ergebnisses einer Berechnung

Book listing lst-0034-book.cpp:

teiler = teiler + 1

Listing 4.20: Eine Zuweisung ist ein Ausdruck mit dem Typ der zugewiesenen Variablen.

Book listing lst-0035-book.cpp:

// https://godbolt.org/z/bh1MsPhje 
#include <iostream>
int main() {
    int a = 3;
    int b = 7 + (a = 12) + 6;   // enthält eine Zuweisung
    std::cout << a << std::endl;
}

Godbolt Listing lst-0035-godb.cpp, https://godbolt.org/z/bh1MsPhje:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bh1MsPhje 
#include <iostream>
int main() {
    int a = 3;
    int b = 7 + (a = 12) + 6;   // enthält eine Zuweisung
    std::cout << a << std::endl;
}

Listing 4.21: Der Compiler hilft, korrekte Programme zu schreiben, indem er die Typen überprüft.

Book listing lst-0036-book.cpp:

// https://godbolt.org/z/9943MfExc 
#include <vector>
class Image {
    std::vector<char> data_;
public:
    void load(const char* filename); // lädt Bilddaten
};
class Screen {
public:
    void show(Image& image);         //                 (ERR)  image sollte const sein
};
void paint(Screen &screen, const Image& image) {
     screen.show(image);
}
int main() {
    Image image {};
    image.load("peter.png");
    Screen screen {};
    paint(screen, image);
}

Godbolt Listing lst-0036-godb.cpp, https://godbolt.org/z/9943MfExc:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9943MfExc 
#include <vector>
class Image {
    std::vector<char> data_;
public:
    void load(const char* filename); // lädt Bilddaten
};
class Screen {
public:
    void show(Image& image);         //                 (ERR)  image sollte const sein
};
void paint(Screen &screen, const Image& image) {
     screen.show(image);
}
int main() {
    Image image {};
    image.load("peter.png");
    Screen screen {};
    paint(screen, image);
}

Listing 4.22: Variablen vom Typ bool können das Ergebnis eines Vergleichs zwischenspeichern.

Book listing lst-0037-book.cpp:

// https://godbolt.org/z/zK9Ke9n48 
#include <iostream>                     // cout
int main(int argc, const char* argv[]) {
    bool mitParametern = argc > 1;      // Vergleichsergebnis zwischengespeichert
    if(mitParametern) {                 // … und verwendet
        std::cout << "Sie haben das Programm mit Parametern aufgerufen.\n";
    }
    return 0;
}

Godbolt Listing lst-0037-godb.cpp, https://godbolt.org/z/zK9Ke9n48:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zK9Ke9n48 
#include <iostream>                     // cout
int main(int argc, const char* argv[]) {
    bool mitParametern = argc > 1;      // Vergleichsergebnis zwischengespeichert
    if(mitParametern) {                 // … und verwendet
        std::cout << "Sie haben das Programm mit Parametern aufgerufen.\n";
    }
    return 0;
}

Listing 4.23: So können Sie einen C++-string als Literal in den Quellcode schreiben.

Book listing lst-0039-book.cpp:

// https://godbolt.org/z/chTTqPjrM 
#include <string>
#include <iostream>
int main() {
    std::cout << "C-Zeichenkettenliteral\n";
    // using std::literals::string_literals::operator""s;
    // using namespace std::string_literals;
    // using namespace std::literals::string_literals;
    using namespace std::literals;
    std::cout << "Echter string\n"s;
}

Godbolt Listing lst-0039-godb.cpp, https://godbolt.org/z/chTTqPjrM:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/chTTqPjrM 
#include <string>
#include <iostream>
int main() {
    std::cout << "C-Zeichenkettenliteral\n";
    // using std::literals::string_literals::operator""s;
    // using namespace std::string_literals;
    // using namespace std::literals::string_literals;
    using namespace std::literals;
    std::cout << "Echter string\n"s;
}

Listing 4.24: Seit C++17 bestimmt der Compiler die Typparameter von Klassentemplates anhand der Konstruktorargumente.

Book listing lst-0041-book.cpp:

// https://godbolt.org/z/GbbcnYbqv 
std::vector vec { 1, 2, 3 };        // statt vector<int>
std::tuple tpl { 5, 'x' };          // statt tuple<int,char>
std::shared_ptr<int> ptr { new int(5) };
std::shared_ptr ptr2 { ptr };       // statt shared_ptr<int>

Godbolt Listing lst-0041-godb.cpp, https://godbolt.org/z/GbbcnYbqv:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/GbbcnYbqv 
std::vector vec { 1, 2, 3 };        // statt vector<int>
std::tuple tpl { 5, 'x' };          // statt tuple<int,char>
std::shared_ptr<int> ptr { new int(5) };
std::shared_ptr ptr2 { ptr };       // statt shared_ptr<int>

Listing 4.25: Manchen Variablen können Sie nichts zuweisen, Sie können sie nur initialisieren.

Book listing lst-0042-book.cpp:

int main() {
     const int fest = 33; // Initialisierung als Konstante
     fest = 80;           //                 (ERR)  eine Zuweisung ist unmöglich
 }

Listing 4.26: Statt des = können Sie {…} zur Initialisierung verwenden.

Book listing lst-0043-book.cpp:

int index = 1;        // alter Stil, sieht wie eine Zuweisung aus
int zaehler { 1 };    // C++11-Stil, eindeutig eine Initialisierung
int counter = { 1 };  // beim C++11-Stil ist das »=« optional und wird ignoriert

Listing 4.27: Sie können einen Namensraum einbinden, um Programmtext kürzer zu machen.

Book listing lst-0050-book.cpp:

#include <iostream>                            // für std::cin, std::cout, std::endl
#include <string>                              // für std::stoi
void berechne(int n) {
    using namespace std;                       // für std::cout und std::endl
    /* Teiler ausgeben */
    cout << "Teiler von " << n << " sind:\n";  // cout statt std::cout
    for(int teiler=1; teiler <= n; ++teiler) {
        if(n % teiler == 0)
            cout << teiler << ", ";            // cout statt std::cout
    }
    cout << endl;
}

Listing 4.28: »using namespace« können Sie auch global verwenden, sollten es aber selten tun.

Book listing lst-0051-book.cpp:

#include <iostream>
#include <string>
using namespace std; //                 (ERR)  wirkt sich global aus; klappt, ist aber kritisch
void berechne(int n) {
    /* Teiler ausgeben */
    cout << "Teiler von " << n << " sind:\n";
    // …
}
// … auch in weiteren Funktionen …

Listing 4.29: Holen Sie sich mit »using« einzelne Bezeichner.

Book listing lst-0052-book.cpp:

#include <iostream>                               // cin, cout, endl
using std::endl;                                  // gilt global in dieser Datei
void berechne(int n) {
    using std::cout;                              // gilt lokal in dieser Funktion
    /* Teiler ausgeben */
    cout << "Teiler von " << n << " sind:\n";
    for(int teiler=1; teiler <= n; ++teiler) {
        if(n % teiler == 0)
            cout << teiler << ", ";
    }
    cout << endl;
}

Listing 4.30: Arithmetische Operatoren in der Anwendung

Book listing lst-0053-book.cpp:

// https://godbolt.org/z/cEGGfoeT7 
#include <iostream>
int main() {
    std::cout << "3+4*5+6=" << 3+4*5+6 << "\n";          // Punkt vor Strich; = 29
    std::cout << "(3+4)*(5+6)=" << (3+4)*(5+6) << "\n";  // Klammern; = 77
    std::cout << "22/7=" << 22/7 << " Rest " << 22%7 << "\n"; // 22/7 = 3 Rest 1
    for(int n=0; n < 10; ++n) {
        std::cout << -2*n*n + 13*n - 4 << " ";           // mit unärem Minus
    }
    std::cout << "\n";
    // Ausgabe: –4 7 14 17 16 11 2 –11 –28 –49
}

Godbolt Listing lst-0053-godb.cpp, https://godbolt.org/z/cEGGfoeT7:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cEGGfoeT7 
#include <iostream>
int main() {
    std::cout << "3+4*5+6=" << 3+4*5+6 << "\n";          // Punkt vor Strich; = 29
    std::cout << "(3+4)*(5+6)=" << (3+4)*(5+6) << "\n";  // Klammern; = 77
    std::cout << "22/7=" << 22/7 << " Rest " << 22%7 << "\n"; // 22/7 = 3 Rest 1
    for(int n=0; n < 10; ++n) {
        std::cout << -2*n*n + 13*n - 4 << " ";           // mit unärem Minus
    }
    std::cout << "\n";
    // Ausgabe: –4 7 14 17 16 11 2 –11 –28 –49
}

Listing 4.31: Programmierbeispiel für die Umwandlung einer Ganzzahl in eine Bitfolge

Book listing lst-0056-book.cpp:

// https://godbolt.org/z/nMcsbxvvv 
#include <iostream>
void printBin(int x) {
    while(x>0) {         // fertig?
        int a = x/2;     // Division durch 2
        int b = x%2;     // Modulo, Rest der Division
        std::cout << x <<" / 2 = " << a << ", Rest " << b<<'\n'; // Ausgabe
        x = a;
    }
}
int main() {
    printBin(412);
}

Godbolt Listing lst-0056-godb.cpp, https://godbolt.org/z/nMcsbxvvv:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/nMcsbxvvv 
#include <iostream>
void printBin(int x) {
    while(x>0) {         // fertig?
        int a = x/2;     // Division durch 2
        int b = x%2;     // Modulo, Rest der Division
        std::cout << x <<" / 2 = " << a << ", Rest " << b<<'\n'; // Ausgabe
        x = a;
    }
}
int main() {
    printBin(412);
}

GodboltId:TTjxzrYf3

Book listing lst-0057-book.cpp:

// https://godbolt.org/z/TTjxzrYf3 
#include <iostream>
#include <bitset>
constexpr unsigned n_bits = sizeof(unsigned short)*8; // 8 Bit pro char
auto bits_umdrehen(unsigned val) -> unsigned short {
  unsigned short ret = 0;
  for (unsigned i = 0; i < n_bits; ++i ) {
    ret = (ret << 1) | (val & 1);   // eins zur Seite, unterstes evtl. setzen
    val >>= 1;                      // eins in die andere Richtung
  }
  return ret;
}
void zeig(unsigned short val) {
    std::bitset<n_bits> bits{val};
    std::cout << val << "=" << bits << " -> ";
    auto lav = bits_umdrehen(val);
    std::bitset<n_bits> stib{lav};
    std::cout << lav << "=" << stib << "\n";
}
int main() {
    zeig(36u);  // Ausgabe: 36=0000000000100100 -> 9216=0010010000000000
    zeig(199u); // Ausgabe: 199=0000000011000111 -> 58112=1110001100000000
    zeig(255u); // Ausgabe: 255=0000000011111111 -> 65280=1111111100000000
    zeig(256u); // Ausgabe: 256=0000000100000000 -> 128=0000000010000000
}

Godbolt Listing lst-0057-godb.cpp, https://godbolt.org/z/TTjxzrYf3:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TTjxzrYf3 
#include <iostream>
#include <bitset>
constexpr unsigned n_bits = sizeof(unsigned short)*8; // 8 Bit pro char
auto bits_umdrehen(unsigned val) -> unsigned short {
  unsigned short ret = 0;
  for (unsigned i = 0; i < n_bits; ++i ) {
    ret = (ret << 1) | (val & 1);   // eins zur Seite, unterstes evtl. setzen
    val >>= 1;                      // eins in die andere Richtung
  }
  return ret;
}
void zeig(unsigned short val) {
    std::bitset<n_bits> bits{val};
    std::cout << val << "=" << bits << " -> ";
    auto lav = bits_umdrehen(val);
    std::bitset<n_bits> stib{lav};
    std::cout << lav << "=" << stib << "\n";
}
int main() {
    zeig(36u);  // Ausgabe: 36=0000000000100100 -> 9216=0010010000000000
    zeig(199u); // Ausgabe: 199=0000000011000111 -> 58112=1110001100000000
    zeig(255u); // Ausgabe: 255=0000000011111111 -> 65280=1111111100000000
    zeig(256u); // Ausgabe: 256=0000000100000000 -> 128=0000000010000000
}

GodboltId:5hqanTeYh

Book listing lst-0059-book.cpp:

// https://godbolt.org/z/5hqanTeYh 
#include <iostream>
#include <bitset>  // hilft bei der Ausgabe von Zahlen als Bitfolge
int main() {
    int a = 0;
    for(int idx=0; idx<8; idx++) {
        a <<= 2;                       // um zwei Bit nach links schieben: "…100"
        a |= 1;                        // unterstes Bit setzen: "…1"
    }
    std::cout << std::bitset<16>(a) << "\n"; // 0101010101010101
    std::cout << a << "\n";            // 21845
}

Godbolt Listing lst-0059-godb.cpp, https://godbolt.org/z/5hqanTeYh:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5hqanTeYh 
#include <iostream>
#include <bitset>  // hilft bei der Ausgabe von Zahlen als Bitfolge
int main() {
    int a = 0;
    for(int idx=0; idx<8; idx++) {
        a <<= 2;                       // um zwei Bit nach links schieben: "…100"
        a |= 1;                        // unterstes Bit setzen: "…1"
    }
    std::cout << std::bitset<16>(a) << "\n"; // 0101010101010101
    std::cout << a << "\n";            // 21845
}

GodboltId:xrMYz93WP

Book listing lst-0068-book.cpp:

// https://godbolt.org/z/xrMYz93WP 
int main() {
    for(int w1 = 1; w1 <= 6; ++w1) { // 1..6
        for(int w2 = 0; w2 < 10; ++w2) { // 0..9
            int max = w1 > w2 ? w1 : w2;  // ternärer Operator
        }
    }
}

Godbolt Listing lst-0068-godb.cpp, https://godbolt.org/z/xrMYz93WP:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xrMYz93WP 
int main() {
    for(int w1 = 1; w1 <= 6; ++w1) { // 1..6
        for(int w2 = 0; w2 < 10; ++w2) { // 0..9
            int max = w1 > w2 ? w1 : w2;  // ternärer Operator
        }
    }
}

Listing 4.32: Mit Kommas in Klammern können Sie mehrere Ausdrücke verketten.

Book listing lst-0069-book.cpp:

// https://godbolt.org/z/rq66cWr3d 
int main() {
    int a = 0;
    int b = 0;
    for(int w1 = 1; w1 <= 6; ++w1) { // 1..6
        for(int w2 = 0; w2 < 10; ++w2) { // 0..9
            int max = w1 > w2 ? (a+=b , w1) :( b+=1 , w2); // Sequenzoperator
        }
    }
}

Godbolt Listing lst-0069-godb.cpp, https://godbolt.org/z/rq66cWr3d:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rq66cWr3d 
int main() {
    int a = 0;
    int b = 0;
    for(int w1 = 1; w1 <= 6; ++w1) { // 1..6
        for(int w2 = 0; w2 < 10; ++w2) { // 0..9
            int max = w1 > w2 ? (a+=b , w1) :( b+=1 , w2); // Sequenzoperator
        }
    }
}

Listing 4.33: In for-Schleifen kann das Sequenzkomma nützlich sein.

Book listing lst-0070-book.cpp:

// https://godbolt.org/z/vd85f7rMj 
#include <iostream>
int main() {
    int arr[] = { 8,3,7,3,11,999,5,6,7 };
    int len = 9;
    for(int i=0, *p=arr; i<len && *p!=999; ++i, ++p) { // erst ++i, dann ++p
        std::cout << i << ":" << *p << " ";
    }
    std::cout << "\n";
    // Ausgabe: 0:8 1:3 2:7 3:3 4:11
}

Godbolt Listing lst-0070-godb.cpp, https://godbolt.org/z/vd85f7rMj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vd85f7rMj 
#include <iostream>
int main() {
    int arr[] = { 8,3,7,3,11,999,5,6,7 };
    int len = 9;
    for(int i=0, *p=arr; i<len && *p!=999; ++i, ++p) { // erst ++i, dann ++p
        std::cout << i << ":" << *p << " ";
    }
    std::cout << "\n";
    // Ausgabe: 0:8 1:3 2:7 3:3 4:11
}

Listing 4.34: Hier werden einige neue Datentypen verwendet.

Book listing lst-0074-book.cpp:

// https://godbolt.org/z/3Y65Ps6G4 
#include <iostream>   // cin, cout für Eingabe und Ausgabe

void eingabe(unsigned &gebTag_,
             unsigned &gebMonat_,
             unsigned &gebJahr_,
             unsigned long long &steuernummer_,
             double &koerperlaenge_) 
{
    /* Eingaben noch ohne gute Fehlerbehandlung... */
    std::cout << "Geb.-Tag: "; std::cin >> gebTag_;
    std::cout << "Geb.-Monat: "; std::cin >> gebMonat_;
    std::cout << "Geb.-Jahr: "; std::cin >> gebJahr_;
    std::cout << "Steuernummer: "; std::cin >> steuernummer_;
    std::cout << "Koerperlaenge: "; std::cin >> koerperlaenge_;
}
int main() {
    /* Daten */
    unsigned gebTag_ = 0;
    unsigned gebMonat_ = 0;
    unsigned gebJahr_ = 0;
    unsigned long long steuernummer_ = 0;
    double koerperlaenge_ = 0.0;
    /* Eingabe */
    eingabe(gebTag_, gebMonat_, gebJahr_, steuernummer_, koerperlaenge_);
    /* Berechnungen */
    // …
}

Godbolt Listing lst-0074-godb.cpp, https://godbolt.org/z/3Y65Ps6G4:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3Y65Ps6G4 
#include <iostream>   // cin, cout für Eingabe und Ausgabe

void eingabe(unsigned &gebTag_,
             unsigned &gebMonat_,
             unsigned &gebJahr_,
             unsigned long long &steuernummer_,
             double &koerperlaenge_) 
{
    /* Eingaben noch ohne gute Fehlerbehandlung... */
    std::cout << "Geb.-Tag: "; std::cin >> gebTag_;
    std::cout << "Geb.-Monat: "; std::cin >> gebMonat_;
    std::cout << "Geb.-Jahr: "; std::cin >> gebJahr_;
    std::cout << "Steuernummer: "; std::cin >> steuernummer_;
    std::cout << "Koerperlaenge: "; std::cin >> koerperlaenge_;
}
int main() {
    /* Daten */
    unsigned gebTag_ = 0;
    unsigned gebMonat_ = 0;
    unsigned gebJahr_ = 0;
    unsigned long long steuernummer_ = 0;
    double koerperlaenge_ = 0.0;
    /* Eingabe */
    eingabe(gebTag_, gebMonat_, gebJahr_, steuernummer_, koerperlaenge_);
    /* Berechnungen */
    // …
}

Listing 4.35: Arithmetik mit Ganzzahlen

Book listing lst-0076-book.cpp:

// https://godbolt.org/z/ebPcdxzvj 
#include <iostream>
int main() {
    std::cout << 3 + 4 * 5 + 6 << "\n";               // 29
    std::cout << 20/7 << " Rest " << 20%7 << "\n";    // 2 Rest 6
}

Godbolt Listing lst-0076-godb.cpp, https://godbolt.org/z/ebPcdxzvj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ebPcdxzvj 
#include <iostream>
int main() {
    std::cout << 3 + 4 * 5 + 6 << "\n";               // 29
    std::cout << 20/7 << " Rest " << 20%7 << "\n";    // 2 Rest 6
}

Listing 4.36: Bitoperationen

Book listing lst-0077-book.cpp:

// https://godbolt.org/z/jeTs5Exqx 
#include <iostream>
int main() {
    unsigned a = 0b1111'0000;       // 240
    unsigned b = 0b0011'1100;       // 60
    std::cout << ( a | b ) << "\n"; // Bit-Oder: 252, in Bits 1111'1100
    std::cout << ( a & b ) << "\n"; // Bit-Und: 48, in Bits 0011'0000
    std::cout << ( a ^ b ) << "\n"; // Exklusiv-Oder: 204, in Bits 1100'1100
    unsigned int c = 170;           // in Bits 0..(24x0)..0'1010'1010
    std::cout << ( ~c ) << "\n";    // Inv.: 4294967125, Bits: 1..(24x1)..1'0101'0101
}

Godbolt Listing lst-0077-godb.cpp, https://godbolt.org/z/jeTs5Exqx:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jeTs5Exqx 
#include <iostream>
int main() {
    unsigned a = 0b1111'0000;       // 240
    unsigned b = 0b0011'1100;       // 60
    std::cout << ( a | b ) << "\n"; // Bit-Oder: 252, in Bits 1111'1100
    std::cout << ( a & b ) << "\n"; // Bit-Und: 48, in Bits 0011'0000
    std::cout << ( a ^ b ) << "\n"; // Exklusiv-Oder: 204, in Bits 1100'1100
    unsigned int c = 170;           // in Bits 0..(24x0)..0'1010'1010
    std::cout << ( ~c ) << "\n";    // Inv.: 4294967125, Bits: 1..(24x1)..1'0101'0101
}

Listing 4.37: Indexvariablen können gut vom Typ »size_t« sein.

Book listing lst-0079-book.cpp:

// https://godbolt.org/z/zGso3xGcj 
#include <vector>
#include <cstddef>  // size_t
int main() {
    std::vector<int> data = {  100, -4, 6'699, 88, 0,  } ;
    int sum = 0;
    for(size_t idx = 0; idx < data.size(); ++idx) { // ein bestimmter int-Typ
        sum += data[idx];
    }
}

Godbolt Listing lst-0079-godb.cpp, https://godbolt.org/z/zGso3xGcj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zGso3xGcj 
#include <vector>
#include <cstddef>  // size_t
int main() {
    std::vector<int> data = {  100, -4, 6'699, 88, 0,  } ;
    int sum = 0;
    for(size_t idx = 0; idx < data.size(); ++idx) { // ein bestimmter int-Typ
        sum += data[idx];
    }
}

Listing 4.41: »double« kann Zahlen nicht immer exakt speichern. Rechnen und Vergleichen mit »==« ist ein Fehler.

Book listing lst-0080-book.cpp:

// https://godbolt.org/z/h86Wh5dbo 
#include <iostream>      // cout
#include <iomanip>       // setprecision, etc.
#include <cmath>         // fabs
using std::cout;         // cout als Abkürzung für std::cout
int main() {
    cout << std::fixed << std::setprecision(25);  // für besser lesbare Ausgabe
    // 0.1 und 0.01 kann double nicht exakt speichern
    double x = 0.1 * 0.1;
    cout << "0.1*0.1: " << x << "\n";
    // Ausgabe: 0.1*0.1: 0.0100000000000000019428903
    if(x == 0.01) {      //                 (ERR)  vergleichen Sie double niemals mit ==
        cout << "Ja! x == 0.01" << "\n";
    } else {
        cout << "Oh-oh! x != 0.01" << "\n";      // Sie sehen diese Ausgabe
    }
    // Achtung vor allem beim Vergleich mit 0.0
    double null = x - 0.01;
    cout << "null: " << null << "\n";
    // Ausgabe: null: 0.0000000000000000017347235
    if(std::fabs(null) < 0.00000001) {           // gegen ein "Epsilon"
        cout << "Ja! null ist nahe 0.0" << "\n"; // Sie sehen diese Ausgabe
    } else {
        cout << "Oh-oh! null nicht nahe 0.0" << "\n";
    }
    // Brüche von 2er-Potenzen sind weniger kritisch
    double y = 0.5 * 0.5; 
    cout << "0.5*0.5: " <<  y << "\n";
    // Ausgabe: 0.5*0.5: 0.2500000000000000000000000
    if(y == 0.25) {    // hier klappt der gefährliche Vergleich ausnahmsweise
        cout << "Ja! y == 0.25" << "\n";         // Sie sehen diese Ausgabe
    } else {
        cout << "Oh-oh! y != 0.25" << "\n";
    }
    //
    return 0;
}

Godbolt Listing lst-0080-godb.cpp, https://godbolt.org/z/h86Wh5dbo:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h86Wh5dbo 
#include <iostream>      // cout
#include <iomanip>       // setprecision, etc.
#include <cmath>         // fabs
using std::cout;         // cout als Abkürzung für std::cout
int main() {
    cout << std::fixed << std::setprecision(25);  // für besser lesbare Ausgabe
    // 0.1 und 0.01 kann double nicht exakt speichern
    double x = 0.1 * 0.1;
    cout << "0.1*0.1: " << x << "\n";
    // Ausgabe: 0.1*0.1: 0.0100000000000000019428903
    if(x == 0.01) {      //                 (ERR)  vergleichen Sie double niemals mit ==
        cout << "Ja! x == 0.01" << "\n";
    } else {
        cout << "Oh-oh! x != 0.01" << "\n";      // Sie sehen diese Ausgabe
    }
    // Achtung vor allem beim Vergleich mit 0.0
    double null = x - 0.01;
    cout << "null: " << null << "\n";
    // Ausgabe: null: 0.0000000000000000017347235
    if(std::fabs(null) < 0.00000001) {           // gegen ein "Epsilon"
        cout << "Ja! null ist nahe 0.0" << "\n"; // Sie sehen diese Ausgabe
    } else {
        cout << "Oh-oh! null nicht nahe 0.0" << "\n";
    }
    // Brüche von 2er-Potenzen sind weniger kritisch
    double y = 0.5 * 0.5; 
    cout << "0.5*0.5: " <<  y << "\n";
    // Ausgabe: 0.5*0.5: 0.2500000000000000000000000
    if(y == 0.25) {    // hier klappt der gefährliche Vergleich ausnahmsweise
        cout << "Ja! y == 0.25" << "\n";         // Sie sehen diese Ausgabe
    } else {
        cout << "Oh-oh! y != 0.25" << "\n";
    }
    //
    return 0;
}

Listing 4.39: Mehrere Möglichkeiten, um »double«-Literale zu kennzeichnen

Book listing lst-0081-book.cpp:

// https://godbolt.org/z/f7T5Y6sd3 
#include <iostream>
#include <iomanip>                              // fixed, setprecision
using std::cout;                                // abgekürzt cout
int main() {
    cout << std::setprecision(2) << std::fixed; // zwei Nachkommastellen
    cout << "1/4: " << 0.25 << "\n";            // Kommaschreibweise für double
    // Ausgabe: 1/4: 0.25

    cout << "2/4: " << 0.5 << "\n";
    // Ausgabe: 2/4: 0.50
    cout << "3/4: " << 0.75 << "\n";
    // Ausgabe: 3/4: 0.75
    cout << "4/4: " << 1 << " oder " << 1.0 << "\n"; //                     (ERR)  erkennt 1 als int
    // Ausgabe 4/4: 1 oder 1.00
    cout << "1e0: " << 1e0 << "\n";             // wissenschaftliche Schreibweise
    // Ausgabe: 1e0: 1.00
    cout << "0x10.1p0: " << 0x10.1p0 << "\n";   // hexadezimale Schreibweise
    // Ausgabe: 0x10.1p0: 16.06
}

Godbolt Listing lst-0081-godb.cpp, https://godbolt.org/z/f7T5Y6sd3:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/f7T5Y6sd3 
#include <iostream>
#include <iomanip>                              // fixed, setprecision
using std::cout;                                // abgekürzt cout
int main() {
    cout << std::setprecision(2) << std::fixed; // zwei Nachkommastellen
    cout << "1/4: " << 0.25 << "\n";            // Kommaschreibweise für double
    // Ausgabe: 1/4: 0.25

    cout << "2/4: " << 0.5 << "\n";
    // Ausgabe: 2/4: 0.50
    cout << "3/4: " << 0.75 << "\n";
    // Ausgabe: 3/4: 0.75
    cout << "4/4: " << 1 << " oder " << 1.0 << "\n"; //                     (ERR)  erkennt 1 als int
    // Ausgabe 4/4: 1 oder 1.00
    cout << "1e0: " << 1e0 << "\n";             // wissenschaftliche Schreibweise
    // Ausgabe: 1e0: 1.00
    cout << "0x10.1p0: " << 0x10.1p0 << "\n";   // hexadezimale Schreibweise
    // Ausgabe: 0x10.1p0: 16.06
}

Listing 4.43: Fließkommaliterale werden irgendwann ungenau.

Book listing lst-0082-book.cpp:

// https://godbolt.org/z/6qfo4oYnr 
#include <iostream>
#include <iomanip> // fixed, setprecision
int main() {
    std::cout << std::setprecision(30) << std::fixed;     // immer 30 Stellen
                                                          // ausgeben
    std::cout <<  1.111222333444555666777888999f << "\n"; // float-Literal
    // Ausgabe: 1.111222386360168457031250000000
    std::cout <<  1.111222333444555666777888999 << "\n";  // double ist Default
    // Ausgabe: 1.111222333444555676607023997349
    std::cout <<  1.111222333444555666777888999d << "\n"; // double-Literal
    // Ausgabe: 1.111222333444555676607023997349
    std::cout <<  1.111222333444555666777888999L << "\n"; // long double
    // Ausgabe: 1.111222333444555666740784227731
}

Godbolt Listing lst-0082-godb.cpp, https://godbolt.org/z/6qfo4oYnr:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6qfo4oYnr 
#include <iostream>
#include <iomanip> // fixed, setprecision
int main() {
    std::cout << std::setprecision(30) << std::fixed;     // immer 30 Stellen
                                                          // ausgeben
    std::cout <<  1.111222333444555666777888999f << "\n"; // float-Literal
    // Ausgabe: 1.111222386360168457031250000000
    std::cout <<  1.111222333444555666777888999 << "\n";  // double ist Default
    // Ausgabe: 1.111222333444555676607023997349
    std::cout <<  1.111222333444555666777888999d << "\n"; // double-Literal
    // Ausgabe: 1.111222333444555676607023997349
    std::cout <<  1.111222333444555666777888999L << "\n"; // long double
    // Ausgabe: 1.111222333444555666740784227731
}

Listing 4.44: Unter anderem können Sie mit »fpclassify« besondere Werte entdecken.

Book listing lst-0083-book.cpp:

// https://godbolt.org/z/v98fWc49E 
#include <iostream>
#include <cmath>  // fpclassify
#include <limits> // numeric_limits
#include <string>
std::string fpklass(double x) {
    switch(std::fpclassify(x)) {
        case FP_INFINITE:  return "unendlich";
        case FP_NAN:       return "NaN";
        case FP_NORMAL:    return "normal";
        case FP_SUBNORMAL: return "subnormal";
        case FP_ZERO:      return "Null";
        default:           return "unbekannt";
    }
}
int main() {
    const auto dmin = std::numeric_limits<double>::min();
    std::cout
      <<"1.0/0.0 ist "<<fpklass(1/0.0)<<'\n'   // Ausgabe: 1.0/0.0 ist unendlich
      <<"0.0/0.0 ist "<<fpklass(0.0/0.0)<<'\n' // Ausgabe: 0.0/0.0 ist NaN
      <<"dmin/2 ist "<<fpklass(dmin/2)<<'\n'   // Ausgabe: dmin/2 ist subnormal
      <<"-0.0 ist "<<fpklass(-0.0)<<'\n'       // Ausgabe: –0.0 ist null
      <<"1.0 ist "<<fpklass(1.0)<<'\n';        // Ausgabe: 1.0 ist normal
}

Godbolt Listing lst-0083-godb.cpp, https://godbolt.org/z/v98fWc49E:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/v98fWc49E 
#include <iostream>
#include <cmath>  // fpclassify
#include <limits> // numeric_limits
#include <string>
std::string fpklass(double x) {
    switch(std::fpclassify(x)) {
        case FP_INFINITE:  return "unendlich";
        case FP_NAN:       return "NaN";
        case FP_NORMAL:    return "normal";
        case FP_SUBNORMAL: return "subnormal";
        case FP_ZERO:      return "Null";
        default:           return "unbekannt";
    }
}
int main() {
    const auto dmin = std::numeric_limits<double>::min();
    std::cout
      <<"1.0/0.0 ist "<<fpklass(1/0.0)<<'\n'   // Ausgabe: 1.0/0.0 ist unendlich
      <<"0.0/0.0 ist "<<fpklass(0.0/0.0)<<'\n' // Ausgabe: 0.0/0.0 ist NaN
      <<"dmin/2 ist "<<fpklass(dmin/2)<<'\n'   // Ausgabe: dmin/2 ist subnormal
      <<"-0.0 ist "<<fpklass(-0.0)<<'\n'       // Ausgabe: –0.0 ist null
      <<"1.0 ist "<<fpklass(1.0)<<'\n';        // Ausgabe: 1.0 ist normal
}

GodboltId:We3oWrcWW

Book listing lst-0086-book.cpp:

// https://godbolt.org/z/We3oWrcWW 
#include <iostream>
#include <cmath>     // sqrt
#include <concepts>  // floating_point
using std::min; using std::max; using std::floating_point;

template<floating_point T> T heron(T a, T b, T c) {
    auto s = (a+b+c) / 2;
    return sqrt(s*(s-a)*(s-b)*(s-c));
}

template<floating_point T> T kahan(T a, T b, T c) {
   auto x = max(a,max(b,c));
   auto y = max(min(a,b), min(max(a,b),c));
   auto z = min(a,min(b,c));
   return sqrt( (x+(y+z))*(z-(x-y))*(z+(x-y))*(x+(y-z)) )/4 ;
}

template<floating_point T> void dreieck(T a, T b, T c) {
   std::cout << "heron: " << heron(a,b,c) << '\n';
   std::cout << "kahan: " << kahan(a,b,c) << '\n';
}

int main() {
   dreieck(3.0f, 4.0f, 5.0f);
}

Godbolt Listing lst-0086-godb.cpp, https://godbolt.org/z/We3oWrcWW:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/We3oWrcWW 
#include <iostream>
#include <cmath>     // sqrt
#include <concepts>  // floating_point
using std::min; using std::max; using std::floating_point;

template<floating_point T> T heron(T a, T b, T c) {
    auto s = (a+b+c) / 2;
    return sqrt(s*(s-a)*(s-b)*(s-c));
}

template<floating_point T> T kahan(T a, T b, T c) {
   auto x = max(a,max(b,c));
   auto y = max(min(a,b), min(max(a,b),c));
   auto z = min(a,min(b,c));
   return sqrt( (x+(y+z))*(z-(x-y))*(z+(x-y))*(x+(y-z)) )/4 ;
}

template<floating_point T> void dreieck(T a, T b, T c) {
   std::cout << "heron: " << heron(a,b,c) << '\n';
   std::cout << "kahan: " << kahan(a,b,c) << '\n';
}

int main() {
   dreieck(3.0f, 4.0f, 5.0f);
}

GodboltId:863b1z4GY

Book listing lst-0087-book.cpp:

// https://godbolt.org/z/863b1z4GY 
int main() {
   std::cout << std::setprecision(15) << std::fixed;
   dreieck(100'000.0f, 99'999.999'79f, 0.000'29f);
   dreieck(100'000.0,  99'999.999'79,  0.000'29);
}

Godbolt Listing lst-0087-godb.cpp, https://godbolt.org/z/863b1z4GY:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/863b1z4GY 
int main() {
   std::cout << std::setprecision(15) << std::fixed;
   dreieck(100'000.0f, 99'999.999'79f, 0.000'29f);
   dreieck(100'000.0,  99'999.999'79,  0.000'29);
}

Listing 4.45: Akkumulierte Zeitmessung

Book listing lst-0088-book.cpp:

// https://godbolt.org/z/drz7fzohh 
#include <iostream>
#include <iomanip> // setprecision, fixed
constexpr int bilderProSek = 25;
constexpr int laufZeitInSek = 3600;
constexpr int bilderInsg = laufZeitInSek * bilderProSek;
constexpr float bildzeit = 1.0f / bilderProSek;

int main() {
    float filmzeit = 0.f;
    for(int n=1; n <= bilderInsg; ++n) { // 1 .. bilderInsg
        filmzeit += bildzeit;// akkumulieren
        // … hier Code für dieses Frame …
    }
    std::cout << std::setprecision(10) << std::fixed
        << filmzeit << '\n'; // Ausgabe: 3602.2695312500
}

Godbolt Listing lst-0088-godb.cpp, https://godbolt.org/z/drz7fzohh:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/drz7fzohh 
#include <iostream>
#include <iomanip> // setprecision, fixed
constexpr int bilderProSek = 25;
constexpr int laufZeitInSek = 3600;
constexpr int bilderInsg = laufZeitInSek * bilderProSek;
constexpr float bildzeit = 1.0f / bilderProSek;

int main() {
    float filmzeit = 0.f;
    for(int n=1; n <= bilderInsg; ++n) { // 1 .. bilderInsg
        filmzeit += bildzeit;// akkumulieren
        // … hier Code für dieses Frame …
    }
    std::cout << std::setprecision(10) << std::fixed
        << filmzeit << '\n'; // Ausgabe: 3602.2695312500
}

Listing 4.46: Geschlossene Zeitberechnung

Book listing lst-0089-book.cpp:

// https://godbolt.org/z/xz6TGdc19 
#include <iostream>
#include <iomanip> // setprecision, fixed
constexpr int bilderProSek = 25;
constexpr int laufZeitInSek = 3600;
constexpr int bilderInsg = laufZeitInSek * bilderProSek;
constexpr float bildzeit = 1.0f / bilderProSek;
int main() {
    float filmzeit = 0.f;
    for(int n=1; n <= bilderInsg; ++n) { // 1 .. bilderInsg, wegen Formel
        filmzeit = bildzeit * n; // skalieren
        // … hier Code für dieses Frame …
    }
    std::cout << std::setprecision(10) << std::fixed
        << filmzeit << '\n';     // Ausgabe: 3600.0000000000
}

Godbolt Listing lst-0089-godb.cpp, https://godbolt.org/z/xz6TGdc19:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xz6TGdc19 
#include <iostream>
#include <iomanip> // setprecision, fixed
constexpr int bilderProSek = 25;
constexpr int laufZeitInSek = 3600;
constexpr int bilderInsg = laufZeitInSek * bilderProSek;
constexpr float bildzeit = 1.0f / bilderProSek;
int main() {
    float filmzeit = 0.f;
    for(int n=1; n <= bilderInsg; ++n) { // 1 .. bilderInsg, wegen Formel
        filmzeit = bildzeit * n; // skalieren
        // … hier Code für dieses Frame …
    }
    std::cout << std::setprecision(10) << std::fixed
        << filmzeit << '\n';     // Ausgabe: 3600.0000000000
}

Listing 4.47: Mit komplexen Zahlen können Sie arithmetisch rechnen.

Book listing lst-0093-book.cpp:

// https://godbolt.org/z/43rYYeKx9 
#include <iostream>
#include <iomanip>    // setprecision, fixed
#include <complex>
using std::cout; using std::complex;

int main() {
    using namespace std::complex_literals;   // für i-Suffix
    cout << std::fixed << std::setprecision(1);
    complex<double> z1 = 1i * 1i;            // i mal i
    cout << z1 << '\n';                      // Ausgabe: (–1.0,0.0)
    complex<double> z2 = std::pow(1i, 2);    // i-Quadrat
    cout << z2 << '\n';                      // Ausgabe: (–1.0,0.0)
    double PI = std::acos(-1);               // Länge eines halben Einheitskreises
    complex<double> z3 = std::exp(1i * PI);  // Euler-Formel
    cout << z3 << '\n';                      // Ausgabe: (–1.0,0.0)
    complex<double> a(3, 4);                 // gewohnt als Konstruktor
    complex<double> b = 1. - 2i;             // praktisch als Literal

    // Berechnungen:
    cout << "a + b = " << a + b << "\n";     // Ausgabe: a + b = (4.0,2.0)
    cout << "a * b = " << a * b << "\n";     // Ausgabe: a * b = (11.0,–2.0)
    cout << "a / b = " << a / b << "\n";     // Ausgabe: a / b = (–1.0,2.0)
    cout << "|a| = "   << abs(a) << "\n";    // Ausgabe: |a| = 5.0
    cout << "conj(a) = " << conj(a) << "\n"; // Ausgabe: conj(a) = (3.0,–4.0)
    cout << "norm(a) = " << norm(a) << "\n"; // Ausgabe: norm(a) = 25.0
    cout << "abs(a) = " << abs(a) << "\n";   // Ausgabe: abs(a) = 5.0
    cout << "exp(a) = " << exp(a) << "\n";   // Ausgabe: exp(a) = (–13.1,–15.2)
}

Godbolt Listing lst-0093-godb.cpp, https://godbolt.org/z/43rYYeKx9:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/43rYYeKx9 
#include <iostream>
#include <iomanip>    // setprecision, fixed
#include <complex>
using std::cout; using std::complex;

int main() {
    using namespace std::complex_literals;   // für i-Suffix
    cout << std::fixed << std::setprecision(1);
    complex<double> z1 = 1i * 1i;            // i mal i
    cout << z1 << '\n';                      // Ausgabe: (–1.0,0.0)
    complex<double> z2 = std::pow(1i, 2);    // i-Quadrat
    cout << z2 << '\n';                      // Ausgabe: (–1.0,0.0)
    double PI = std::acos(-1);               // Länge eines halben Einheitskreises
    complex<double> z3 = std::exp(1i * PI);  // Euler-Formel
    cout << z3 << '\n';                      // Ausgabe: (–1.0,0.0)
    complex<double> a(3, 4);                 // gewohnt als Konstruktor
    complex<double> b = 1. - 2i;             // praktisch als Literal

    // Berechnungen:
    cout << "a + b = " << a + b << "\n";     // Ausgabe: a + b = (4.0,2.0)
    cout << "a * b = " << a * b << "\n";     // Ausgabe: a * b = (11.0,–2.0)
    cout << "a / b = " << a / b << "\n";     // Ausgabe: a / b = (–1.0,2.0)
    cout << "|a| = "   << abs(a) << "\n";    // Ausgabe: |a| = 5.0
    cout << "conj(a) = " << conj(a) << "\n"; // Ausgabe: conj(a) = (3.0,–4.0)
    cout << "norm(a) = " << norm(a) << "\n"; // Ausgabe: norm(a) = 25.0
    cout << "abs(a) = " << abs(a) << "\n";   // Ausgabe: abs(a) = 5.0
    cout << "exp(a) = " << exp(a) << "\n";   // Ausgabe: exp(a) = (–13.1,–15.2)
}

Listing 4.48: Ausgabe in unspezifizierter Reihenfolge

Book listing lst-0095-book.cpp:

// https://godbolt.org/z/eW1cfYcGs 
#include <iostream>
void ausgabe(int a, int b) {
    std::cout << a << ' ' << b << '\n';
}
int zahl() {
    static int val = 0;
    return ++val;
}
int main() {
    ausgabe(zahl(), zahl()); // in welcher Reihenfolge?
}

Godbolt Listing lst-0095-godb.cpp, https://godbolt.org/z/eW1cfYcGs:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eW1cfYcGs 
#include <iostream>
void ausgabe(int a, int b) {
    std::cout << a << ' ' << b << '\n';
}
int zahl() {
    static int val = 0;
    return ++val;
}
int main() {
    ausgabe(zahl(), zahl()); // in welcher Reihenfolge?
}

Listing 5.1: Einrückung vier, Klammern in Zeile mit Schlüsselwort, wenige Leerzeichen

Book listing lst-0097-book.cpp:

// https://godbolt.org/z/eP77v498E 
#include <iostream>
int func(int arg1, int arg2) {
    if(arg1 > arg2) {
        return arg1-arg2;
    } else {
        return arg2-arg1;
    }
}
int main(int argc, const char* argv[]) {
    for(int x=0; x<10; ++x) {
        for(int y=0; y<10; ++y) {
            std::cout << func(x,y) << " ";
        }
        std::cout << "\n";
    }
}

Godbolt Listing lst-0097-godb.cpp, https://godbolt.org/z/eP77v498E:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eP77v498E 
#include <iostream>
int func(int arg1, int arg2) {
    if(arg1 > arg2) {
        return arg1-arg2;
    } else {
        return arg2-arg1;
    }
}
int main(int argc, const char* argv[]) {
    for(int x=0; x<10; ++x) {
        for(int y=0; y<10; ++y) {
            std::cout << func(x,y) << " ";
        }
        std::cout << "\n";
    }
}

Listing 5.2: Einrückung zwei, Klammern nur wenn nötig und in eigener Zeile, mehr Leerzeichen

Book listing lst-0098-book.cpp:

// https://godbolt.org/z/4TMn37qhE 
#include <iostream>
int func ( int arg1, int arg2 )
{
  if (arg1 > arg2)
    return arg1 - arg2;
  else
    return arg2 - arg1;
}
int main ( int argc, const char *argv[] )
{
  for ( int x = 0 ; x < 10 ; ++x )
  {
    for ( int y = 0 ; y < 10 ; ++y )
      std::cout << func ( x, y ) << " ";
    std::cout << "\n";
  }
}

Godbolt Listing lst-0098-godb.cpp, https://godbolt.org/z/4TMn37qhE:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4TMn37qhE 
#include <iostream>
int func ( int arg1, int arg2 )
{
  if (arg1 > arg2)
    return arg1 - arg2;
  else
    return arg2 - arg1;
}
int main ( int argc, const char *argv[] )
{
  for ( int x = 0 ; x < 10 ; ++x )
  {
    for ( int y = 0 ; y < 10 ; ++y )
      std::cout << func ( x, y ) << " ";
    std::cout << "\n";
  }
}

Listing 6.1: Einige Verwendungsmöglichkeiten von Strings

Book listing lst-0099-book.cpp:

// https://godbolt.org/z/vMvs47nfs 
#include <iostream>       // cin, cout für Eingabe und Ausgabe
#include <string>         // Sie benötigen diesen Header der Standardbibliothek

void eingabe(
    std::string &name,    // als Parameter
    unsigned &gebJahr)
{
    /* Eingaben noch ohne gute Fehlerbehandlung... */
    std::cout << "Name: ";
    std::getline(std::cin, name); // getline liest in einen String ein
    if(name.length() == 0) {      // length ist eine Methode von string
        std::cout << "Sie haben einen leeren Namen eingegeben.\n";
        exit(1);
    }
    std::cout << "Geb.-Jahr: ";
    std::cin >> gebJahr;
}
int main() {
    /* Daten */
    std::string name;             // definiert und initialisiert eine string-Variable
    unsigned gebJahr = 0;
    /* Eingabe */
    eingabe(name, gebJahr);
    /* Berechnungen */
    // …
}

Godbolt Listing lst-0099-godb.cpp, https://godbolt.org/z/vMvs47nfs:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vMvs47nfs 
#include <iostream>       // cin, cout für Eingabe und Ausgabe
#include <string>         // Sie benötigen diesen Header der Standardbibliothek

void eingabe(
    std::string &name,    // als Parameter
    unsigned &gebJahr)
{
    /* Eingaben noch ohne gute Fehlerbehandlung... */
    std::cout << "Name: ";
    std::getline(std::cin, name); // getline liest in einen String ein
    if(name.length() == 0) {      // length ist eine Methode von string
        std::cout << "Sie haben einen leeren Namen eingegeben.\n";
        exit(1);
    }
    std::cout << "Geb.-Jahr: ";
    std::cin >> gebJahr;
}
int main() {
    /* Daten */
    std::string name;             // definiert und initialisiert eine string-Variable
    unsigned gebJahr = 0;
    /* Eingabe */
    eingabe(name, gebJahr);
    /* Berechnungen */
    // …
}

Listing 6.2: Eine string_view lässt sich aus einen string leicht erzeugen.

Book listing lst-0102-book.cpp:

// https://godbolt/.org/z/bdaE5nf5T 
#include <iostream>
#include <string>
#include <string_view>
void zeige_mitte(std::string_view msg) {     // string_view ist ein guter Parameter
   auto mitte = msg.substr(2, msg.size()-4); // substr liefert string_view zurück
   std::cout << mitte << "\n";
}
int main() {
    using namespace std::literals;
    const std::string aaa = "##Etwas Text##"s;
    zeige_mitte(aaa);                        // Umwandlung in string_view
    auto bbb = "++Mehr Text++"sv;            // string_view als Literal
    zeige_mitte(bbb);
}

Listing 6.3: Der Fehlerstream ist von der Standardausgabe getrennt.

Book listing lst-0103-book.cpp:

// https://godbolt/.org/z/raYaeY357 
// Rufen Sie dieses Programm zum Beispiel mit 'prog.exe > datei.txt' auf.
#include <iostream>  // cout, cerr
int main() {
    std::cout << "Ausgabe nach cout\n";      // wird nach 'datei.txt' ausgegeben
    std::cerr << "Fehlermeldung!\n";         // erscheint trotzdem auf der Konsole
    std::cout << "Wieder normale Ausgabe\n"; // wieder in die Datei
}

Listing 6.4: Eine Funktion mit Ein- und Ausgabe

Book listing lst-0104-book.cpp:

// https://godbolt/.org/z/Gbe7aM4o4 
#include <iostream>                      // cin, cout für Eingabe und Ausgabe
#include <string>
#include <array>
using std::cin; using std::cout;         // Abkürzungen cin und cout
void eingabe(
    std::string &name,
    unsigned &gebTag,
    unsigned &gebMonat,
    unsigned &gebJahr,
    long long &steuernummer,
    std::array<int,12> &monatseinkommen) // array ist ein Container
{
    /* Eingaben noch ohne gute Fehlerbehandlung… */
    cout << "Name: ";
    std::getline(cin, name);   // getline nimmt Eingabestrom und String
    if(name.length() == 0) {
        cout << "Sie haben einen leeren Namen eingegeben.\n";
        exit(1);
    }
    cout << "Geb.-Tag: "; cin >> gebTag;
    cout << "Geb.-Monat: "; cin >> gebMonat;
    cout << "Geb.-Jahr: "; cin >> gebJahr;
    cout << "Steuernummer: "; cin >> steuernummer;
    for(int m=0; m<12; ++m) {
        cout << "Einkommen Monat " << m+1 << ": "; // mehrere Ausgaben
        cin >> monatseinkommen[m];                 // Einlesen mit Operator
    }
    cout << std::endl;
}
int main() {
    std::string name{};
    unsigned tag = 0;
    unsigned monat = 0;
    unsigned jahr = 0;
    long long stNr = 0;
    std::array<int,12> einkommen{};
    eingabe(name, tag, monat, jahr, stNr, einkommen);
    // … Berechnungen …
}

GodboltId:a6qqbWKMs

Book listing lst-0105-book.cpp:

//https://godbolt.org/z/a6qqbWKMs 
#include <cstdlib>
#include <iostream>

int main(int argc, char* argv[]) {
    for(int i=1; i<argc; ++i) {                // Start bei 1
        for(char* p=argv[i]; *p!='\0'; ++p) {
            char c = toupper(*p);
            std::cout << c;
        }
        std::cout << ' ';
    }
    std::cout << '\n';
}

Godbolt Listing lst-0105-godb.cpp, https://godbolt.org/z/a6qqbWKMs:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
//https://godbolt.org/z/a6qqbWKMs 
#include <cstdlib>
#include <iostream>

int main(int argc, char* argv[]) {
    for(int i=1; i<argc; ++i) {                // Start bei 1
        for(char* p=argv[i]; *p!='\0'; ++p) {
            char c = toupper(*p);
            std::cout << c;
        }
        std::cout << ' ';
    }
    std::cout << '\n';
}

GodboltId:McqfcWb8j

Book listing lst-0106-book.cpp:

//https://godbolt.org/z/McqfcWb8j 
#include <fstream>
int main(int argc, char* argv[]) {
    std::ofstream meineAusgabe{"output1.txt"};
    meineAusgabe << "Zeile 1\n";
    meineAusgabe << "Zeile 2\n";
}

Godbolt Listing lst-0106-godb.cpp, https://godbolt.org/z/McqfcWb8j:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
//https://godbolt.org/z/McqfcWb8j 
#include <fstream>
int main(int argc, char* argv[]) {
    std::ofstream meineAusgabe{"output1.txt"};
    meineAusgabe << "Zeile 1\n";
    meineAusgabe << "Zeile 2\n";
}

GodboltId:P9z8n8v16

Book listing lst-0107-book.cpp:

//https://godbolt.org/z/P9z8n8v16 
#include <fstream>
int main(int argc, char* argv[]) {
    int wert = 0;
    std::ifstream meineEingabe{"input1.txt"};
    meineEingabe >> wert;
}

Godbolt Listing lst-0107-godb.cpp, https://godbolt.org/z/P9z8n8v16:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
//https://godbolt.org/z/P9z8n8v16 
#include <fstream>
int main(int argc, char* argv[]) {
    int wert = 0;
    std::ifstream meineEingabe{"input1.txt"};
    meineEingabe >> wert;
}

Listing 6.5: Verwenden Sie den !-Operator, um den Zustand des Streams zu prüfen.

Book listing lst-0108-book.cpp:

//https://godbolt.org/z/ssW3eKEGq 
#include <iostream> // cerr
#include <fstream>
int main(int argc, char* argv[]) {
    int wert;
    std::ifstream meineEingabe{"input1.txt"};
    if(!meineEingabe) {
        std::cerr << "Fehler beim Öffnen der Datei!\n";
    } else {
        meineEingabe >> wert;
    }
}

Godbolt Listing lst-0108-godb.cpp, https://godbolt.org/z/ssW3eKEGq:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
//https://godbolt.org/z/ssW3eKEGq 
#include <iostream> // cerr
#include <fstream>
int main(int argc, char* argv[]) {
    int wert;
    std::ifstream meineEingabe{"input1.txt"};
    if(!meineEingabe) {
        std::cerr << "Fehler beim Öffnen der Datei!\n";
    } else {
        meineEingabe >> wert;
    }
}

Listing 6.6: Verwenden Sie Streammanipulatoren aus , um das Format der Ausgabe zu beeinflussen.

Book listing lst-0109-book.cpp:

//https://godbolt.org/z/EcnWz3r3j 
#include <iostream>
#include <iomanip>                   // fixed, setprecision
#include <format>                    // C++20
using std::cout; using std::format;  // Abkürzung cout, format
int main() {
    cout << std::fixed               // Punktschreibweise, nicht wissenschaftlich
         << std::setprecision(15);   // 15 Nachkommastellen
    cout << 0.5 << "\n";             // Ausgabe: 0.500000000000000*
    cout << std::setprecision(5);    // 5 Nachkommastellen
    cout << 0.25 << "\n";            // Ausgabe: 0.25000
    cout << format("{:0.4f}", 0.75) << "\n"; // (C++20) Ausgabe: 0.7500
    return 0;
}

Godbolt Listing lst-0109-godb.cpp, https://godbolt.org/z/EcnWz3r3j:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
//https://godbolt.org/z/EcnWz3r3j 
#include <iostream>
#include <iomanip>                   // fixed, setprecision
#include <format>                    // C++20
using std::cout; using std::format;  // Abkürzung cout, format
int main() {
    cout << std::fixed               // Punktschreibweise, nicht wissenschaftlich
         << std::setprecision(15);   // 15 Nachkommastellen
    cout << 0.5 << "\n";             // Ausgabe: 0.500000000000000*
    cout << std::setprecision(5);    // 5 Nachkommastellen
    cout << 0.25 << "\n";            // Ausgabe: 0.25000
    cout << format("{:0.4f}", 0.75) << "\n"; // (C++20) Ausgabe: 0.7500
    return 0;
}

Listing 6.7: In einem »array« speichern Sie eine feste Anzahl Elemente.

Book listing lst-0112-book.cpp:

// https://godbolt.org/z/cd1d1W7T1 
#include <array>
#include <iostream>
using std::cout; using std::array; using std::string;
int main() {
  array<string,7> wotag = { "Montag", "Dienstag",        // definieren
      "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag" };
  cout << "Die Woche beginnt mit " << wotag[0] << ".\n"; // Werte lesen
  cout << "Sie endet mit " << wotag.at(6) << ".\n";      // sicheres Werte lesen
  /* nordisch? */
  wotag[5] = "Sonnabend";                                // Werte verändern
}

Godbolt Listing lst-0112-godb.cpp, https://godbolt.org/z/cd1d1W7T1:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cd1d1W7T1 
#include <array>
#include <iostream>
using std::cout; using std::array; using std::string;
int main() {
  array<string,7> wotag = { "Montag", "Dienstag",        // definieren
      "Mittwoch", "Donnerstag", "Freitag", "Samstag", "Sonntag" };
  cout << "Die Woche beginnt mit " << wotag[0] << ".\n"; // Werte lesen
  cout << "Sie endet mit " << wotag.at(6) << ".\n";      // sicheres Werte lesen
  /* nordisch? */
  wotag[5] = "Sonnabend";                                // Werte verändern
}

Listing 6.8: Die Arraygröße muss konstant sein.

Book listing lst-0113-book.cpp:

// https://godbolt.org/z/zfe7dM4ex 
#include <array>
#include <iostream>
constexpr size_t MONATE = 12; /* Monate im Jahr */
int main() {
    std::array<unsigned,MONATE> mtage = {     // okay mit einer Konstante
        31,28,31,30,31,30,31,31,30,31,30,31};
    unsigned alter = 0;
    std::cout << "Wie alt sind Sie? "; std::cin >> alter;
    std::array<int,alter> lebensjahre;       // Arraygröße geht nicht per Variable
}

Godbolt Listing lst-0113-godb.cpp, https://godbolt.org/z/zfe7dM4ex:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zfe7dM4ex 
#include <array>
#include <iostream>
constexpr size_t MONATE = 12; /* Monate im Jahr */
int main() {
    std::array<unsigned,MONATE> mtage = {     // okay mit einer Konstante
        31,28,31,30,31,30,31,31,30,31,30,31};
    unsigned alter = 0;
    std::cout << "Wie alt sind Sie? "; std::cin >> alter;
    std::array<int,alter> lebensjahre;       // Arraygröße geht nicht per Variable
}

Listing 6.9: Wenn Sie eine Arraydefinition mehrfach verwenden müssen, dann verwenden Sie »using«.

Book listing lst-0114-book.cpp:

// https://godbolt.org/z/a4zxbd99z 
#include <array>
#include <algorithm>                    // accumulate
#include <numeric>                      // iota
using Januar = std::array<int,31>;      // Alias für wiederholte Verwendung

void initJanuar(Januar& jan) {          // das genaue Array als Parameter
    std::iota(begin(jan), end(jan), 1); // füllt mit  1, 2, 3 … 31
}
int sumJanuar(const Januar& jan) {      // das genaue Array als Parameter
    return std::accumulate(begin(jan), end(jan), 0); // Hilfsfunktion für Summe
}
int main() {
    Januar jan;                         // deklariert ein array<int,31>
    initJanuar( jan );
    int sum = sumJanuar( jan );
}

Godbolt Listing lst-0114-godb.cpp, https://godbolt.org/z/a4zxbd99z:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a4zxbd99z 
#include <array>
#include <algorithm>                    // accumulate
#include <numeric>                      // iota
using Januar = std::array<int,31>;      // Alias für wiederholte Verwendung

void initJanuar(Januar& jan) {          // das genaue Array als Parameter
    std::iota(begin(jan), end(jan), 1); // füllt mit  1, 2, 3 … 31
}
int sumJanuar(const Januar& jan) {      // das genaue Array als Parameter
    return std::accumulate(begin(jan), end(jan), 0); // Hilfsfunktion für Summe
}
int main() {
    Januar jan;                         // deklariert ein array<int,31>
    initJanuar( jan );
    int sum = sumJanuar( jan );
}

GodboltId:T9jsEoMj4

Book listing lst-0115-book.cpp:

// https://godbolt.org/z/T9jsEoMj4 
#include <vector>                    // Sie benötigen diesen Header
int main() {
    std::vector<int> quadrate{};     // leer initialisieren
    for(int idx = 0; idx<100; ++idx) {
        quadrate.push_back(idx*idx); // Anfügen eines Elements
    }
}

Godbolt Listing lst-0115-godb.cpp, https://godbolt.org/z/T9jsEoMj4:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/T9jsEoMj4 
#include <vector>                    // Sie benötigen diesen Header
int main() {
    std::vector<int> quadrate{};     // leer initialisieren
    for(int idx = 0; idx<100; ++idx) {
        quadrate.push_back(idx*idx); // Anfügen eines Elements
    }
}

Listing 6.10: Die einfachste Iteration benutzt eine bereichsbasierte »for«-Schleife.

Book listing lst-0116-book.cpp:

// https://godbolt.org/z/hhhavG5he 
#include <vector>
#include <iostream>                     // cout, endl
int main() {
    std::vector quadrate{1,4,9,16,25};  // gefüllt initialisieren
    for(int zahl : quadrate)  // zahl ist ein Quadrat nach dem anderen
        std::cout << zahl << " ";
    std::cout << std::endl;
}

Godbolt Listing lst-0116-godb.cpp, https://godbolt.org/z/hhhavG5he:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hhhavG5he 
#include <vector>
#include <iostream>                     // cout, endl
int main() {
    std::vector quadrate{1,4,9,16,25};  // gefüllt initialisieren
    for(int zahl : quadrate)  // zahl ist ein Quadrat nach dem anderen
        std::cout << zahl << " ";
    std::cout << std::endl;
}

Listing 6.11: Der Zugriff auf die Elemente per Index

Book listing lst-0117-book.cpp:

// https://godbolt.org/z/xcKM7v1Eo 
#include <vector>
#include <iostream>                           // cout, endl
int main() {
  std::vector qus{1,4,9,16,25};
  for(unsigned idx=0; idx<qus.size(); ++idx)  // size enthält die Anzahl
    std::cout << qus[idx] << " ";             // [idx] oder at(idx) holt ein Element
  std::cout << std::endl;
}

Godbolt Listing lst-0117-godb.cpp, https://godbolt.org/z/xcKM7v1Eo:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xcKM7v1Eo 
#include <vector>
#include <iostream>                           // cout, endl
int main() {
  std::vector qus{1,4,9,16,25};
  for(unsigned idx=0; idx<qus.size(); ++idx)  // size enthält die Anzahl
    std::cout << qus[idx] << " ";             // [idx] oder at(idx) holt ein Element
  std::cout << std::endl;
}

Listing 6.12: Der Einsatz von Iteratoren für eine Schleife

Book listing lst-0118-book.cpp:

// https://godbolt.org/z/1WG8zvhYe 
#include <vector>
#include <iostream>                  // cout, endl
int main() {
  std::vector qus{1,4,9,16,25};
  for(auto it = qus.begin(); it!=qus.end(); ++it) // zwischen begin() und end()
    std::cout << *it << " ";         // mit *it kommen Sie vom Iterator zum Element
  std::cout << std::endl;
}

Godbolt Listing lst-0118-godb.cpp, https://godbolt.org/z/1WG8zvhYe:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1WG8zvhYe 
#include <vector>
#include <iostream>                  // cout, endl
int main() {
  std::vector qus{1,4,9,16,25};
  for(auto it = qus.begin(); it!=qus.end(); ++it) // zwischen begin() und end()
    std::cout << *it << " ";         // mit *it kommen Sie vom Iterator zum Element
  std::cout << std::endl;
}

Listing 6.13: Zählen mit einem Algorithmus

Book listing lst-0119-book.cpp:

// https://godbolt.org/z/4G67rso8T 
#include <vector>
#include <algorithm>                           // count_if
#include <numeric>                             // iota
#include <iostream>
bool even(int n) { return n%2==0; }            // Test auf gerade
int main() {
    std::vector<int> data(100);                // 100 x null
    std::iota(data.begin(), data.end(), 0);    // 0, 1, 2, … 99
    // zählt gerade Zahlen
    std::cout << std::count_if(data.begin(), data.end(), even);
}

Godbolt Listing lst-0119-godb.cpp, https://godbolt.org/z/4G67rso8T:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4G67rso8T 
#include <vector>
#include <algorithm>                           // count_if
#include <numeric>                             // iota
#include <iostream>
bool even(int n) { return n%2==0; }            // Test auf gerade
int main() {
    std::vector<int> data(100);                // 100 x null
    std::iota(data.begin(), data.end(), 0);    // 0, 1, 2, … 99
    // zählt gerade Zahlen
    std::cout << std::count_if(data.begin(), data.end(), even);
}

Listing 7.1: Funktionen verwenden

Book listing lst-0127-book.cpp:

// https://godbolt.org/z/5ssc6W5o6 
#include <iostream>              // cout
#include <cmath>                 // sin
#include <string>
#include <vector>
using std::sin;
int main() {
    std::cout << "sin(0.0): " << sin(0.0) << "\n";  // Aufruf von sin() mit Literal
    double winkel = 3.1415/2;
    std::cout << "sin("<<winkel<<"): "<<sin(winkel)<<"\n"; // Aufruf mit Variable
    std::string name = "Han Solo";
    std::cout << name.length() << "\n"; // Aufruf einer Methode
                                        // … konzeptionell wie length(name)
    std::vector<int> data{};
    data.push_back(5);                 // weiterer Methodenaufruf mit Parameter
    data.push_back(10);
    std::cout << data.back() << " ";
    data.pop_back();
    std::cout << data.back() << "\n";
    data.pop_back();
}

Godbolt Listing lst-0127-godb.cpp, https://godbolt.org/z/5ssc6W5o6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5ssc6W5o6 
#include <iostream>              // cout
#include <cmath>                 // sin
#include <string>
#include <vector>
using std::sin;
int main() {
    std::cout << "sin(0.0): " << sin(0.0) << "\n";  // Aufruf von sin() mit Literal
    double winkel = 3.1415/2;
    std::cout << "sin("<<winkel<<"): "<<sin(winkel)<<"\n"; // Aufruf mit Variable
    std::string name = "Han Solo";
    std::cout << name.length() << "\n"; // Aufruf einer Methode
                                        // … konzeptionell wie length(name)
    std::vector<int> data{};
    data.push_back(5);                 // weiterer Methodenaufruf mit Parameter
    data.push_back(10);
    std::cout << data.back() << " ";
    data.pop_back();
    std::cout << data.back() << "\n";
    data.pop_back();
}

Listing 7.2: Verschiedene Rückgabetypen von Funktionen

Book listing lst-0128-book.cpp:

int func();                        // liefert einen int zurück
std::string func();                // eine Zeichenkette aus der Standardbibliothek
void func();                       // kein Rückgabewert
std::pair<int,std::string> func(); // zusammengesetzter Typ aus der Stdlib
vector<int> func();                // liefert einen neuen Container zurück
vector<int>& func();               // Verweis auf anderen Container
const vector<int>& func();         // ebenso, aber Sie können ihn nicht verändern

Listing 7.3: Parameter werden zunächst als Wert übergeben.

Book listing lst-0129-book.cpp:

// https://godbolt.org/z/8zcvMdM3b 
#include <iostream>

void print_val8(int n) {            // Parameter als Wert
    std::cout << n << " ";
    n = 8;                          // setzt Parameter auf 8
    std::cout << n << "\n";
}

int main() {
    int x = 5;
    print_val8(x);                  // x als Wert: druckt 5, dann 8
    std::cout << x << "\n";         // x ist unverändert 5
    print_val8(42);                 // 42 als Wert: druckt 42, dann 8
}

Godbolt Listing lst-0129-godb.cpp, https://godbolt.org/z/8zcvMdM3b:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8zcvMdM3b 
#include <iostream>

void print_val8(int n) {            // Parameter als Wert
    std::cout << n << " ";
    n = 8;                          // setzt Parameter auf 8
    std::cout << n << "\n";
}

int main() {
    int x = 5;
    print_val8(x);                  // x als Wert: druckt 5, dann 8
    std::cout << x << "\n";         // x ist unverändert 5
    print_val8(42);                 // 42 als Wert: druckt 42, dann 8
}

Listing 7.4: Als Referenzparameter fügen Sie ein »&« hinzu.

Book listing lst-0130-book.cpp:

// https://godbolt.org/z/63dTshz3Y 
#include <iostream>
void print_ref8(int& n) {           // Parameter als Referenz
    std::cout << n << " ";
    n = 8;                          // setzt Parameter auf 8
    std::cout << n << "\n";
}
int main() {
    int x = 5;
    print_ref8(x);                  // x als Referenz: druckt 5, dann 8
    std::cout << x << "\n";         // x ist nun 8
}

Godbolt Listing lst-0130-godb.cpp, https://godbolt.org/z/63dTshz3Y:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/63dTshz3Y 
#include <iostream>
void print_ref8(int& n) {           // Parameter als Referenz
    std::cout << n << " ";
    n = 8;                          // setzt Parameter auf 8
    std::cout << n << "\n";
}
int main() {
    int x = 5;
    print_ref8(x);                  // x als Referenz: druckt 5, dann 8
    std::cout << x << "\n";         // x ist nun 8
}

Listing 7.5: Konstante Referenzen als Parameter können Sie für jeden Aufruf verwenden.

Book listing lst-0131-book.cpp:

// https://godbolt.org/z/dcKnx3Pno 
#include <iostream>
void print_cref(const int& n) {     // Parameter als konstante Referenz
    std::cout << n << " ";
}

int main() {
    int x = 5;
    print_cref(x);                  // Aufruf mit einer Variablen
    print_cref(42);                 // Aufruf mit einem konstanten Literal
}

Godbolt Listing lst-0131-godb.cpp, https://godbolt.org/z/dcKnx3Pno:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dcKnx3Pno 
#include <iostream>
void print_cref(const int& n) {     // Parameter als konstante Referenz
    std::cout << n << " ";
}

int main() {
    int x = 5;
    print_cref(x);                  // Aufruf mit einer Variablen
    print_cref(42);                 // Aufruf mit einem konstanten Literal
}

GodboltId:fTvT5sKqY

Book listing lst-0133-book.cpp:

// https://godbolt.org/z/fTvT5sKqY 
#include <iostream>
void verdopple(double &zahl) {     // Ausgabeparameter als veränderbare Referenz
    zahl *= 2.0;
}

int main() {
    double zahl = 7.25;
    verdopple(zahl);
    std::cout << zahl << "\n";     // nun 14.5
}

Godbolt Listing lst-0133-godb.cpp, https://godbolt.org/z/fTvT5sKqY:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fTvT5sKqY 
#include <iostream>
void verdopple(double &zahl) {     // Ausgabeparameter als veränderbare Referenz
    zahl *= 2.0;
}

int main() {
    double zahl = 7.25;
    verdopple(zahl);
    std::cout << zahl << "\n";     // nun 14.5
}

GodboltId:caExoc36Y

Book listing lst-0134-book.cpp:

// https://godbolt.org/z/caExoc36Y 
#include <iostream>
double verdopple(double zahl) {    // Wertparameter und Rückgabewert
    return zahl * 2.0;
}
int main() {
    double zahl = 7.25;
    zahl = verdopple(zahl);        // Änderung ausgedrückt durch Rückgabewert
    std::cout << zahl << "\n";     // auch 14.5
}

Godbolt Listing lst-0134-godb.cpp, https://godbolt.org/z/caExoc36Y:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/caExoc36Y 
#include <iostream>
double verdopple(double zahl) {    // Wertparameter und Rückgabewert
    return zahl * 2.0;
}
int main() {
    double zahl = 7.25;
    zahl = verdopple(zahl);        // Änderung ausgedrückt durch Rückgabewert
    std::cout << zahl << "\n";     // auch 14.5
}

Listing 7.6: Verschiedene Definitionen von Funktionen

Book listing lst-0135-book.cpp:

std::vector<int> prims = {2};        // globale Variable
bool testeObPrim(int n) {            // eigene Funktion
    for(int teil : prims) {          // Zugriff auf globale Variable
        if(teil*teil > n)            // Zugriff auf Parameter
            return true;
        if(n%teil==0)
            return false;
    }
    return true;
}
void berechnePrimsBis(int bis) {     // noch eine eigene Funktion
    for(int n=3; n<bis; n=n+2) {
        if(testeObPrim(n)) {         // eigene Funktion verwenden
            prims.push_back(n);
        }
    }
}

Listing 7.7: Eine Vorwärtsdeklaration ohne Funktionskörper

Book listing lst-0136-book.cpp:

// … Auszug …
bool testeObPrim(int n);           // Deklaration der später definierten Funktion
void berechnePrimsBis(int bis) {
    for(int n=3; n<bis; n=n+2) {
        if(testeObPrim(n)) {       // Verwendung der später definierten Funktion
            prims.push_back(n);
        }
    }
}
bool testeObPrim(int n) {          // Definition erst nach der Verwendung
    // … wie zuvor …
}

Listing 7.8: Hier finden einige Umwandlungen statt. Die Umwandlungen können auf Ihrem System anders aussehen.

Book listing lst-0138-book.cpp:

// https://godbolt.org/z/6hWvqhY7W 
#include <iostream>
#include <format>
void prints(short s, int i, float f, double d) {
  std::cout << std::format("short: {} int: {} float: {:.2f} double: {:.2f}\n",
    s, i, f, d);
}
int main() {
  int mill = 1000*1000;                // 1 Million
  prints(mill, mill, mill, mill);      // short läuft über
  // Ausgabe: short: 16960 int: 1000000 float: 1000000.00 double: 1000000.00
  long bill = 1000L*1000L*1000L*1000L; // 1 Billion
  prints(bill, bill, bill, bill);      // sogar int läuft über, float wird ungenau
  // Ausgabe: short: 4096 int: –727379968 
  // float: 999999995904.00 double: 1000000000000.00
  float drei = 3.75f;
  prints(drei, drei, drei, drei);     // Nachkommastellen gehen verloren
  // Ausgabe: short: 3 int: 3 float: 3.75 double: 3.75
}

Godbolt Listing lst-0138-godb.cpp, https://godbolt.org/z/6hWvqhY7W:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6hWvqhY7W 
#include <iostream>
#include <format>
void prints(short s, int i, float f, double d) {
  std::cout << std::format("short: {} int: {} float: {:.2f} double: {:.2f}\n",
    s, i, f, d);
}
int main() {
  int mill = 1000*1000;                // 1 Million
  prints(mill, mill, mill, mill);      // short läuft über
  // Ausgabe: short: 16960 int: 1000000 float: 1000000.00 double: 1000000.00
  long bill = 1000L*1000L*1000L*1000L; // 1 Billion
  prints(bill, bill, bill, bill);      // sogar int läuft über, float wird ungenau
  // Ausgabe: short: 4096 int: –727379968 
  // float: 999999995904.00 double: 1000000000000.00
  float drei = 3.75f;
  prints(drei, drei, drei, drei);     // Nachkommastellen gehen verloren
  // Ausgabe: short: 3 int: 3 float: 3.75 double: 3.75
}

Listing 7.9: Die Funktionen »print« und »add« wurden für mehrere Typen überladen.

Book listing lst-0140-book.cpp:

// https://godbolt.org/z/9YcPraT15 
#include <iostream>
void print(int wert) { std::cout << "int-Wert: " << wert << "\n"; }
void print(double wert) { std::cout << "double-Wert: " << wert << "\n"; }
void print(int w1, double w2) { std::cout << "Werte: "<<w1<<", "<<w2<<"\n"; }
int add(int n, int m) { return n + m; }
double add(double a, double b) { return a + b; }
int main() {
    print( add(3, 4) );        // add(int, int) und print(int)
    print( add(3.25f, 1.5f) ); // add(double, double) und print(double)
    print( 7, 3.25 );          // print(int, double)
}

Godbolt Listing lst-0140-godb.cpp, https://godbolt.org/z/9YcPraT15:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9YcPraT15 
#include <iostream>
void print(int wert) { std::cout << "int-Wert: " << wert << "\n"; }
void print(double wert) { std::cout << "double-Wert: " << wert << "\n"; }
void print(int w1, double w2) { std::cout << "Werte: "<<w1<<", "<<w2<<"\n"; }
int add(int n, int m) { return n + m; }
double add(double a, double b) { return a + b; }
int main() {
    print( add(3, 4) );        // add(int, int) und print(int)
    print( add(3.25f, 1.5f) ); // add(double, double) und print(double)
    print( 7, 3.25 );          // print(int, double)
}

GodboltId:58cTfvYhe

Book listing lst-0143-book.cpp:

// https://godbolt.org/z/58cTfvYhe 
int zwei() { return 2; }      //             (ERR)  einmal int als Rückgabetyp…
double zwei() { return 2.0; } //             (ERR)  … und einmal double
int main() {
    int x = zwei();
    double y = zwei();
}

Godbolt Listing lst-0143-godb.cpp, https://godbolt.org/z/58cTfvYhe:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/58cTfvYhe 
int zwei() { return 2; }      //             (ERR)  einmal int als Rückgabetyp…
double zwei() { return 2.0; } //             (ERR)  … und einmal double
int main() {
    int x = zwei();
    double y = zwei();
}

GodboltId:evGqG1oqa

Book listing lst-0144-book.cpp:

// https://godbolt.org/z/evGqG1oqa 
int verdopple(int a) { return a * 2; }
double verdopple(double a) { return a * 2.0; }
int main() {
    int x = verdopple(7);
    double y = verdopple(7.0);
}

Godbolt Listing lst-0144-godb.cpp, https://godbolt.org/z/evGqG1oqa:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/evGqG1oqa 
int verdopple(int a) { return a * 2; }
double verdopple(double a) { return a * 2.0; }
int main() {
    int x = verdopple(7);
    double y = verdopple(7.0);
}

Listing 7.10: Defaultparameter wirken wie mehrere Überladungen.

Book listing lst-0147-book.cpp:

// https://godbolt.org/z/fjc37rvEr 
int add(int n=0, int m=0, int o=0, int p=0, int q=0) {
    return n+m+o+p+q;
}
int main() {
    std::cout << add(1,2,3,4,5) << "\n";
    std::cout << add(1,2,3,4) << "\n"; // wie add(1,2,3,4,0)
    std::cout << add(1,2,3) << "\n";   // wie add(1,2,3,0,0)
    std::cout << add(1,2) << "\n";     // wie add(1,2,0,0,0)
    std::cout << add(1) << "\n";       // wie add(1,0,0,0,0)
    std::cout << add() << "\n";        // wie add(0,0,0,0,0)
}

Godbolt Listing lst-0147-godb.cpp, https://godbolt.org/z/fjc37rvEr:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fjc37rvEr 
int add(int n=0, int m=0, int o=0, int p=0, int q=0) {
    return n+m+o+p+q;
}
int main() {
    std::cout << add(1,2,3,4,5) << "\n";
    std::cout << add(1,2,3,4) << "\n"; // wie add(1,2,3,4,0)
    std::cout << add(1,2,3) << "\n";   // wie add(1,2,3,0,0)
    std::cout << add(1,2) << "\n";     // wie add(1,2,0,0,0)
    std::cout << add(1) << "\n";       // wie add(1,0,0,0,0)
    std::cout << add() << "\n";        // wie add(0,0,0,0,0)
}

Listing 7.11: Alternative Syntax für Funktionsdeklarationen mit nachgestelltem Rückgabetyp

Book listing lst-0152-book.cpp:

auto func() -> int;
auto func() -> std::string;
auto func() -> void;
auto func() -> std::pair<int,std::string>;
auto func() -> vector<int>;
auto func() -> vector<int>&;
auto func() -> const vector<int>&;

Listing 7.12: Seit C++14 können Sie den Rückgabetyp durch den Compiler ermitteln lassen.

Book listing lst-0153-book.cpp:

// https://godbolt.org/z/6d5fxn9ed 
auto maxOf2(int a, int b) {
    return a<b ? b : a;   // ein return: der Compiler ermittelt int
}
auto minOf3(int a, int b, int c) {
     if(a<b) return a<c ? a : c;
     else return b<c ? b : c;
}
auto medianOf3(int a, int b, int c) {
     // komplexer, aber kein Problem für den Compiler
     return minOf3(maxOf2(a,b), maxOf2(b,c), maxOf2(a,c));
}

Godbolt Listing lst-0153-godb.cpp, https://godbolt.org/z/6d5fxn9ed:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6d5fxn9ed 
auto maxOf2(int a, int b) {
    return a<b ? b : a;   // ein return: der Compiler ermittelt int
}
auto minOf3(int a, int b, int c) {
     if(a<b) return a<c ? a : c;
     else return b<c ? b : c;
}
auto medianOf3(int a, int b, int c) {
     // komplexer, aber kein Problem für den Compiler
     return minOf3(maxOf2(a,b), maxOf2(b,c), maxOf2(a,c));
}

GodboltId:dMvqG85fr

Book listing lst-0157-book.cpp:

// https://godbolt.org/z/dMvqG85fr 
double add(double a, double b) { return a + b; }
double add(int, int) = delete;   // add(3,4) verbieten

Godbolt Listing lst-0157-godb.cpp, https://godbolt.org/z/dMvqG85fr:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dMvqG85fr 
double add(double a, double b) { return a + b; }
double add(int, int) = delete;   // add(3,4) verbieten

GodboltId:8Gdso36zf

Book listing lst-0158-book.cpp:

// https://godbolt.org/z/8Gdso36zf 
class Widget : public Base {
    explicit Widget(int);     // keine automatische Konvertierung von int
    ~Widget();                // Destruktor mit ~ vor dem Namen
    virtual void update();    // vorangestelltes virtual
    void calc1() override;    // nachgestelltes override
    void calc2() final;       // nachgestelltes final
    void draw() const;        // nachgestelltes const
    virtual void paint() = 0; // abstrakte Methode
};

Godbolt Listing lst-0158-godb.cpp, https://godbolt.org/z/8Gdso36zf:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8Gdso36zf 
class Widget : public Base {
    explicit Widget(int);     // keine automatische Konvertierung von int
    ~Widget();                // Destruktor mit ~ vor dem Namen
    virtual void update();    // vorangestelltes virtual
    void calc1() override;    // nachgestelltes override
    void calc2() final;       // nachgestelltes final
    void draw() const;        // nachgestelltes const
    virtual void paint() = 0; // abstrakte Methode
};

Listing 8.1: Berechnet alle Primzahlen in einem von Benutzern bestimmten Bereich

Book listing lst-0159-book.cpp:

// https://godbolt.org/z/3hf7h67Pe 
#include <iostream>                   // cout
#include <vector>                     // Container vector
#include <string>                     // stoi
int eingabeBis(int argc, const char* argv[]) {
    /* Zahl ermitteln */
    int bis = 0;                      // neue Variable einführen
    if(argc<=1) {                     // if-Anweisung mit then- und else-Block
        std::cout << "Bis wohin wollen Sie Primzahlen berechnen? ";
        if(!(std::cin >> bis)) {      // Prüfen des Rückgabewerts
            return -1;                // Fehler bei Benutzereingabe
        }
    } else {                          // else-Teil der if-Anweisung
        bis = std::stoi(argv[1]);
    }
    return bis;                       // Eingabe zurückliefern
}
std::vector prims{2};                 // neuer vector<int> mit Initialisierung
bool testeObPrim(int n) {
    /* prims muss aufsteigend sortiert sein */
    for(int teil : prims) {           // bereichsbasierte for-Schleife
        if(teil*teil > n)             // zu groß, um überhaupt Teiler zu sein?
            return true;              // … dann innere Schleife vorzeitig beenden
        if(n%teil==0)                 // ist Teiler?
            return false;             // … dann raus
    }
    return true;                      // kein Teiler gefunden
}
void berechnePrimsBis(int bis) {
    /* Prims-Berechnung */
    /* vector muss an dieser Stelle {2} enthalten */
    for(int n=3; n<bis; n=n+2) {      // Standard-for-Schleife
        if(testeObPrim(n)) {
            prims.push_back(n);       // ist prim – merken als Teiler und Ergebnis
        }
    }
}
void ausgabePrims() {
    for(int prim : prims) {           // bereichsbasiert, über alle Elemente
        std::cout << prim << " ";
    }
    std::cout << "\n";
}
int main(int argc, const char* argv[]) {
    int bis = eingabeBis(argc, argv); // deklariert Variable
    if(bis < 2) { return 1; }         // Raus aus main mit Nicht-okay-Wert.
    berechnePrimsBis(bis);
    ausgabePrims();
    return 0;
}

Godbolt Listing lst-0159-godb.cpp, https://godbolt.org/z/3hf7h67Pe:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3hf7h67Pe 
#include <iostream>                   // cout
#include <vector>                     // Container vector
#include <string>                     // stoi
int eingabeBis(int argc, const char* argv[]) {
    /* Zahl ermitteln */
    int bis = 0;                      // neue Variable einführen
    if(argc<=1) {                     // if-Anweisung mit then- und else-Block
        std::cout << "Bis wohin wollen Sie Primzahlen berechnen? ";
        if(!(std::cin >> bis)) {      // Prüfen des Rückgabewerts
            return -1;                // Fehler bei Benutzereingabe
        }
    } else {                          // else-Teil der if-Anweisung
        bis = std::stoi(argv[1]);
    }
    return bis;                       // Eingabe zurückliefern
}
std::vector prims{2};                 // neuer vector<int> mit Initialisierung
bool testeObPrim(int n) {
    /* prims muss aufsteigend sortiert sein */
    for(int teil : prims) {           // bereichsbasierte for-Schleife
        if(teil*teil > n)             // zu groß, um überhaupt Teiler zu sein?
            return true;              // … dann innere Schleife vorzeitig beenden
        if(n%teil==0)                 // ist Teiler?
            return false;             // … dann raus
    }
    return true;                      // kein Teiler gefunden
}
void berechnePrimsBis(int bis) {
    /* Prims-Berechnung */
    /* vector muss an dieser Stelle {2} enthalten */
    for(int n=3; n<bis; n=n+2) {      // Standard-for-Schleife
        if(testeObPrim(n)) {
            prims.push_back(n);       // ist prim – merken als Teiler und Ergebnis
        }
    }
}
void ausgabePrims() {
    for(int prim : prims) {           // bereichsbasiert, über alle Elemente
        std::cout << prim << " ";
    }
    std::cout << "\n";
}
int main(int argc, const char* argv[]) {
    int bis = eingabeBis(argc, argv); // deklariert Variable
    if(bis < 2) { return 1; }         // Raus aus main mit Nicht-okay-Wert.
    berechnePrimsBis(bis);
    ausgabePrims();
    return 0;
}

Listing 8.2: Dieses »for« bezieht sich auf nur eine Anweisung.

Book listing lst-0160-book.cpp:

for(int prim : prims)               // for gefolgt von einer Anweisung
    std::cout << prim << " ";
std::cout << "\n";                  // nicht mehr Teil von for

Listing 8.3: Ein Anweisungsblock wird in { und } eingeschlossen.

Book listing lst-0161-book.cpp:

for(int prim : prims) {             // Beginn des Blocks
    std::cout << prim;
    std::cout << " ";
}                                   // Ende des Blocks
std::cout << "\n";

Listing 8.4: Wo Anweisungen erlaubt sind, können Sie auch einen Block erstellen.

Book listing lst-0162-book.cpp:

if(zahl > 50) {                     // äußerer Block
    {                               // 1. innerer Block
        int ergebnis = zahl*zahl;
        std::cout << "Quadrat: " << ergebnis << std::endl;
    }
    {                               // 2. innerer Block
        int ergebnis = zahl+zahl;
        std::cout << "Verdoppelt: " << ergebnis << std::endl;
    }
}

Listing 8.5: Zweimal »ergebnis« als neue Variable in einem Block geht nicht.

Book listing lst-0163-book.cpp:

if(zahl > 50) {
    int ergebnis = zahl*zahl;           // Definition von ergebnis
    std::cout << "Quadrat: " << ergebnis << std::endl;
    int ergebnis = zahl+zahl;           //             (ERR)  Fehler: ergebnis wurde schon definiert
    std::cout << "Verdoppelt: " << ergebnis << std::endl;
}

Listing 8.6: Sehr viele Variablen sind auch nicht gut.

Book listing lst-0164-book.cpp:

if(zahl > 50) {
    int ergebnis1 = zahl*zahl;          // ein Ergebnis
    std::cout << "Quadrat: " << ergebnis << std::endl;
    int ergebnis2 = zahl+zahl;          // noch ein Ergebnis
    std::cout << "Verdoppelt: " << ergebnis << std::endl;
    int ergebnis3 = zahl+zahl+zahl;     // und noch ein Ergebnis
    // … viele Zeilen Code dazwischen …
    // und hier?
    // … noch mehr Programmzeilen …
}

Listing 8.7: Leere Anweisungen, wohin das Auge schaut

Book listing lst-0165-book.cpp:

int main() {  ;;;              // 3 leere Anweisungen
    int zahl = 12 ; ;          // 1 leere Anweisung
    ; int q = zahl*zahl ;      // 1 leere Anweisung
    if(q>50) {
        q = q - 50;
    } ;                        // 1 leere Anweisung
    std::cout << q << std::endl;
}

Listing 8.8: Mit auto können Sie auch mehrere Variablen gleichzeitig initialisieren.

Book listing lst-0172-book.cpp:

// https://godbolt.org/z/G7P4ErTE1 
#include <iostream>
#include <tuple> // make_tuple
auto mkTpl() {
    return std::make_tuple(2, 'b', 3.14); // tuple<int,char,double>
}
struct Point {
    int x, y;
};
int main() {
    // Strukuriertes Binden eines C-Arrays
    int ungerade[5] = { 1,3,7,9,11 };
    auto [ eins, zwei, drei, vier, fuenf ] = ungerade;
    // Strukuriertes Binden eines Tupels
    auto [ two, bee, pi ] = mkTpl();
    // Strukuriertes Binden einer Struktur
    Point p0{  10, 15 };
    auto [ the_x, the_y ] = p0;
}

Godbolt Listing lst-0172-godb.cpp, https://godbolt.org/z/G7P4ErTE1:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/G7P4ErTE1 
#include <iostream>
#include <tuple> // make_tuple
auto mkTpl() {
    return std::make_tuple(2, 'b', 3.14); // tuple<int,char,double>
}
struct Point {
    int x, y;
};
int main() {
    // Strukuriertes Binden eines C-Arrays
    int ungerade[5] = { 1,3,7,9,11 };
    auto [ eins, zwei, drei, vier, fuenf ] = ungerade;
    // Strukuriertes Binden eines Tupels
    auto [ two, bee, pi ] = mkTpl();
    // Strukuriertes Binden einer Struktur
    Point p0{  10, 15 };
    auto [ the_x, the_y ] = p0;
}

GodboltId:YTTE96rfc

Book listing lst-0173-book.cpp:

// https://godbolt.org/z/YTTE96rfc 
int main() {
    int ungerade[5] = { 1,3,7,9,11 };
    auto &[ eins, zwei, drei, vier, fuenf ] = ungerade;
    auto &[ two, bee, pi ] = mkTpl(); //             (ERR)  kein &-Binden an Tempwerte
    Point p0{  10, 15 };
    auto &[ the_x, the_y ] = p0;
}

Godbolt Listing lst-0173-godb.cpp, https://godbolt.org/z/YTTE96rfc:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YTTE96rfc 
int main() {
    int ungerade[5] = { 1,3,7,9,11 };
    auto &[ eins, zwei, drei, vier, fuenf ] = ungerade;
    auto &[ two, bee, pi ] = mkTpl(); //             (ERR)  kein &-Binden an Tempwerte
    Point p0{  10, 15 };
    auto &[ the_x, the_y ] = p0;
}

Listing 8.9: Dies sind alles Ausdrücke, die als Anweisung eingesetzt werden.

Book listing lst-0174-book.cpp:

bis = 99;                     // eine Zuweisung ist ein Ausdruck
bis = bis * 2 + 1;            // Zuweisung mit einer Berechnung verbinden
berechnePrimsBis(bis);        // ein Funktionsaufruf ist ein Ausdruck
std::cout << "Friedrich III"; // der Ausgabeoperator

Listing 8.10: Diese if-Anweisungen enthalten Initialisierer.

Book listing lst-0180-book.cpp:

// https://godbolt.org/z/d6PscKx4M 
#include <map>
#include <string>
#include <algorithm> // any_of
#include <iostream>  // cerr
std::map<int, std::string> m;
int main() {
   if(auto it = m.find(10); it != m.end()) { return it->second.size(); }
   if(char buf[10]={0}; std::fgets(buf, 10, stdin)) { m[0] += buf; }
   std::string s;
   if(auto keywords = {"if", "for", "while"};
       std::any_of(keywords.begin(), keywords.end(),
       [&s](const char* kw) { return s == kw; })) {
           std::cerr << "Fehler\n";
   }
}

Godbolt Listing lst-0180-godb.cpp, https://godbolt.org/z/d6PscKx4M:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/d6PscKx4M 
#include <map>
#include <string>
#include <algorithm> // any_of
#include <iostream>  // cerr
std::map<int, std::string> m;
int main() {
   if(auto it = m.find(10); it != m.end()) { return it->second.size(); }
   if(char buf[10]={0}; std::fgets(buf, 10, stdin)) { m[0] += buf; }
   std::string s;
   if(auto keywords = {"if", "for", "while"};
       std::any_of(keywords.begin(), keywords.end(),
       [&s](const char* kw) { return s == kw; })) {
           std::cerr << "Fehler\n";
   }
}

Listing 8.11: Der Compiler kann die Bedingung zur Compilezeit berechnen.

Book listing lst-0181-book.cpp:

// https://godbolt.org/z/Ycse4EWav 
#include <iostream> // cout

template<typename T>
void speicher(T x) {
    if constexpr(sizeof(T) > 4) {
       std::cout << "Braucht viel Speicher: " << x << " \n";
    }
}

constexpr auto DEBUG = true;
int main() {
    if constexpr(DEBUG) {
        std::cout << "Debug ist an.\n";
    }
    speicher<long long>(44LL);
}

Godbolt Listing lst-0181-godb.cpp, https://godbolt.org/z/Ycse4EWav:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Ycse4EWav 
#include <iostream> // cout

template<typename T>
void speicher(T x) {
    if constexpr(sizeof(T) > 4) {
       std::cout << "Braucht viel Speicher: " << x << " \n";
    }
}

constexpr auto DEBUG = true;
int main() {
    if constexpr(DEBUG) {
        std::cout << "Debug ist an.\n";
    }
    speicher<long long>(44LL);
}

Listing 8.12: Die Schleife wird 100-mal durchlaufen.

Book listing lst-0182-book.cpp:

// https://godbolt.org/z/Gc53z6K1W 
#include <iostream>
int main() {
    /* Summiere 1 bis 100 auf */
    int summe = 0;
    int zahl = 1;
    while(zahl <= 100)       // Bedingung
    {                        // Block, der wiederholt ausgeführt wird
        summe += zahl;       // fürs Ergebnis
        zahl += 1;           // nächste Zahl
    }                        // Ende des wiederholten Blocks
    std::cout << summe << std::endl;
}

Godbolt Listing lst-0182-godb.cpp, https://godbolt.org/z/Gc53z6K1W:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Gc53z6K1W 
#include <iostream>
int main() {
    /* Summiere 1 bis 100 auf */
    int summe = 0;
    int zahl = 1;
    while(zahl <= 100)       // Bedingung
    {                        // Block, der wiederholt ausgeführt wird
        summe += zahl;       // fürs Ergebnis
        zahl += 1;           // nächste Zahl
    }                        // Ende des wiederholten Blocks
    std::cout << summe << std::endl;
}

Listing 8.13: Der Rumpf einer »do-while«-Schleife wird mindestens einmal ausgeführt.

Book listing lst-0184-book.cpp:

// https://godbolt.org/z/6hh5KhExM 
#include <iostream>                 // cin
#include <string>
int main() {
    std::string line;
    do {                            // mindestens einmal getline ausführen
       std::getline(std::cin, line);
       if(!std::cin) break;         // Fehler oder Dateiende
    } while(line != "quit");        // Ende bei bestimmter Eingabe
}

Godbolt Listing lst-0184-godb.cpp, https://godbolt.org/z/6hh5KhExM:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6hh5KhExM 
#include <iostream>                 // cin
#include <string>
int main() {
    std::string line;
    do {                            // mindestens einmal getline ausführen
       std::getline(std::cin, line);
       if(!std::cin) break;         // Fehler oder Dateiende
    } while(line != "quit");        // Ende bei bestimmter Eingabe
}

Listing 8.14: Summe mit einer »for«-Schleife

Book listing lst-0185-book.cpp:

// https://godbolt.org/z/7foYcMMaz 
#include <iostream>
int main() {
    /* Summiere 1 bis 100 auf */
    int summe = 0;
    for(int zahl=1; zahl <= 100; zahl+=1) {   // kompakt
        summe += zahl;                        // fürs Ergebnis
    }
    std::cout << summe << std::endl;
}

Godbolt Listing lst-0185-godb.cpp, https://godbolt.org/z/7foYcMMaz:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7foYcMMaz 
#include <iostream>
int main() {
    /* Summiere 1 bis 100 auf */
    int summe = 0;
    for(int zahl=1; zahl <= 100; zahl+=1) {   // kompakt
        summe += zahl;                        // fürs Ergebnis
    }
    std::cout << summe << std::endl;
}

Listing 8.15: »for«-Schleife mit leerem Initialisierungsteil

Book listing lst-0186-book.cpp:

// https://godbolt.org/z/185ha3q3f 
#include <iostream>
int main() {
    /* Summiere 1 bis 100 auf */
    int summe = 0;
    int zahl = 1;                         // Initialisierung vor der Schleife
    for(  ; zahl <= 100; zahl=zahl+1) {   // leere Initialisierung
        summe = summe + zahl;
    }
    std::cout << zahl << std::endl;       // zahl gibt es nun noch außerhalb
}

Godbolt Listing lst-0186-godb.cpp, https://godbolt.org/z/185ha3q3f:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/185ha3q3f 
#include <iostream>
int main() {
    /* Summiere 1 bis 100 auf */
    int summe = 0;
    int zahl = 1;                         // Initialisierung vor der Schleife
    for(  ; zahl <= 100; zahl=zahl+1) {   // leere Initialisierung
        summe = summe + zahl;
    }
    std::cout << zahl << std::endl;       // zahl gibt es nun noch außerhalb
}

Listing 8.16: Schleifen ohne Bedingung müssen irgendwie anders beendet werden.

Book listing lst-0187-book.cpp:

int main() {
    for( ; ; ) {  // kein Init, keine Bedingung, kein Update – also für immer
        /* ... Benutzereingabe */
        /* ... falls Benutzer Quit wählt, Programmende */
        /* ... ansonsten, Berechnung und Ausgabe */
    }
}

Listing 8.17: Die bereichsbasierte »for«-Schleife erkennen Sie an dem Doppelpunkt.

Book listing lst-0188-book.cpp:

// Auszug
std::vector<int> prims{2};   // vector ist ein Container, bereit für Ranged For
void testeObPrim(int n) {
    /* prims muss aufsteigend sortiert sein */
    for(int teil : prims) {   // bereichsbasierte for-Schleife
        if(teil*teil > n)
            return true;
        if(n%teil==0)
            return false;
    }
    return true;
}
// …

void ausgabePrims() {
    for(int i=1; int prim : prims) {   // bereichsbasierte for-Schleife
        std::cout << i++ << ". Primzahl: " <<prim << " ";
    }
    std::cout << "\n";
}
// …

Listing 8.18: Jeder »case« deckt einen Fall ab, und nirgendwo wurde das »break« vergessen.

Book listing lst-0189-book.cpp:

// https://godbolt.org/z/5oe38obPr 
#include <string>
#include <vector>
#include <iostream>       // cout

void rechner(std::ostream& out, std::string input) {
    std::vector<int> stapel {};
    for(char c : input) {
        if(c>='0' && c<='9') {
            stapel.push_back( c-'0' ); // Zahlenwert des Zeichens
            continue;     // nächste Schleifeniteration
        }
        int top = 0;
        int second = 0;
        switch(c) {       // Bedingung auf zeichen
        case '+':
            top = stapel.back(); stapel.pop_back();
            second = stapel.back(); stapel.pop_back();
            stapel.push_back(second + top);
            break;
        case '-':
            top = stapel.back(); stapel.pop_back();
            second = stapel.back(); stapel.pop_back();
            stapel.push_back(second - top);
            break;
        case '*':
            top = stapel.back(); stapel.pop_back();
            second = stapel.back(); stapel.pop_back();
            stapel.push_back(second * top);
            break;
        case '=':
            for(int elem : stapel) { out << elem; }
            out << "\n";
            break;
        case ' ':
            break;
        default:
            out << "\n'" << c << "' verstehe ich nicht.\n";
        } /* switch */
    } /* for c */
}
int main(int argc, const char* argv[]) {
    if(argc > 1) {
        rechner(std::cout, argv[1]);
    } else {
        // 3 + 4 * 5 + 6 mit Punkt- vor Strichrechnung ergibt 29
        rechner(std::cout, "345*+6+=");
    }
}

Godbolt Listing lst-0189-godb.cpp, https://godbolt.org/z/5oe38obPr:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5oe38obPr 
#include <string>
#include <vector>
#include <iostream>       // cout

void rechner(std::ostream& out, std::string input) {
    std::vector<int> stapel {};
    for(char c : input) {
        if(c>='0' && c<='9') {
            stapel.push_back( c-'0' ); // Zahlenwert des Zeichens
            continue;     // nächste Schleifeniteration
        }
        int top = 0;
        int second = 0;
        switch(c) {       // Bedingung auf zeichen
        case '+':
            top = stapel.back(); stapel.pop_back();
            second = stapel.back(); stapel.pop_back();
            stapel.push_back(second + top);
            break;
        case '-':
            top = stapel.back(); stapel.pop_back();
            second = stapel.back(); stapel.pop_back();
            stapel.push_back(second - top);
            break;
        case '*':
            top = stapel.back(); stapel.pop_back();
            second = stapel.back(); stapel.pop_back();
            stapel.push_back(second * top);
            break;
        case '=':
            for(int elem : stapel) { out << elem; }
            out << "\n";
            break;
        case ' ':
            break;
        default:
            out << "\n'" << c << "' verstehe ich nicht.\n";
        } /* switch */
    } /* for c */
}
int main(int argc, const char* argv[]) {
    if(argc > 1) {
        rechner(std::cout, argv[1]);
    } else {
        // 3 + 4 * 5 + 6 mit Punkt- vor Strichrechnung ergibt 29
        rechner(std::cout, "345*+6+=");
    }
}

Listing 8.19: Sehr selten gibt es »case«-Blöcke ohne »break«, noch seltener sinnvolle.

Book listing lst-0190-book.cpp:

// https://godbolt.org/z/jaMTcshEf 
#include <iostream>
#include <string>

using std::string; using std::cout;

void rateMonat(unsigned welchenTagHabenwirHeute) {
    switch(welchenTagHabenwirHeute) {
    /* fehlende break-Anweisungen: Fall-through beabsichtigt */
    default:
        if(welchenTagHabenwirHeute>31) {
            cout << "Sie schummeln";
            break;
        }
    case 28:
    case 29:
        cout << "Feb ";
    case 30:
        cout << "Apr Jun Sep Nov ";
    case 31:
        cout << "Jan Mar Mai Jul Aug Okt Dez ";
    }

    cout << ".\n";
}
int main() {
    rateMonat(31); // wenn wir heute den 31. hätten?
    // Ausgabe: Jan Mar Mai Jul Aug Okt Dez .
    rateMonat(30); // wenn es der 30. wäre?
    // Ausgabe: Apr Jun Sep Nov Jan Mar Mai Jul Aug Okt Dez .
    rateMonat(4);
    // Ausgabe: Feb Apr Jun Sep Nov Jan Mar Mai Jul Aug Okt Dez .
    rateMonat(77);
    // Ausgabe: Sie schummeln.
}

Godbolt Listing lst-0190-godb.cpp, https://godbolt.org/z/jaMTcshEf:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jaMTcshEf 
#include <iostream>
#include <string>

using std::string; using std::cout;

void rateMonat(unsigned welchenTagHabenwirHeute) {
    switch(welchenTagHabenwirHeute) {
    /* fehlende break-Anweisungen: Fall-through beabsichtigt */
    default:
        if(welchenTagHabenwirHeute>31) {
            cout << "Sie schummeln";
            break;
        }
    case 28:
    case 29:
        cout << "Feb ";
    case 30:
        cout << "Apr Jun Sep Nov ";
    case 31:
        cout << "Jan Mar Mai Jul Aug Okt Dez ";
    }

    cout << ".\n";
}
int main() {
    rateMonat(31); // wenn wir heute den 31. hätten?
    // Ausgabe: Jan Mar Mai Jul Aug Okt Dez .
    rateMonat(30); // wenn es der 30. wäre?
    // Ausgabe: Apr Jun Sep Nov Jan Mar Mai Jul Aug Okt Dez .
    rateMonat(4);
    // Ausgabe: Feb Apr Jun Sep Nov Jan Mar Mai Jul Aug Okt Dez .
    rateMonat(77);
    // Ausgabe: Sie schummeln.
}

Listing 8.20: Mit break beenden Sie eine Schleife vorzeitig.

Book listing lst-0191-book.cpp:

// https://godbolt.org/z/75h9Y95vf 
#include <iostream>                // cout
int main() {
    for(int x=1; x<20; x+=1) {     // äußere for-Schleife
        for(int y=1; y<20; y+=1) { // innere for-Schleife
            int prod = x*y;
            if(prod>=100) {
                break;             // raus aus innerer y-Schleife
            }
            std::cout << prod << " ";
        } /* Ende for y */
        // Ziel von break
    } /* Ende for x */                // erste wirkliche Zeile nach break
    std::cout << "\n";
}

Godbolt Listing lst-0191-godb.cpp, https://godbolt.org/z/75h9Y95vf:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/75h9Y95vf 
#include <iostream>                // cout
int main() {
    for(int x=1; x<20; x+=1) {     // äußere for-Schleife
        for(int y=1; y<20; y+=1) { // innere for-Schleife
            int prod = x*y;
            if(prod>=100) {
                break;             // raus aus innerer y-Schleife
            }
            std::cout << prod << " ";
        } /* Ende for y */
        // Ziel von break
    } /* Ende for x */                // erste wirkliche Zeile nach break
    std::cout << "\n";
}

Listing 8.21: Mit »return« wird die aktuelle Funktion verlassen. Falls nötig, geben Sie einen Wert für die Rückgabe mit an.

Book listing lst-0192-book.cpp:

// https://godbolt.org/z/5ddxa9v1j 
#include <iostream>                      // cout
int min3(int x, int y, int z) {          // Funktion liefert einen int zurück
    if(x<y) {
        if(x<z) return x;
        else return z;
    } else if(y<z) {
        return y;
    }
    else return z;
}
void printMin(int x, int y, int z) {     // Funktion liefert nichts zurück
    if(x<0 || y<0 || z<0) {
        std::cout << "Bitte nur Zahlen groesser 0\n";
        return;
    }
    std::cout << min3(x,y,z) << "\n";
}                                        // hier steht kein return
int main() {
    printMin(3, -4, 8);
    printMin(6, 77, 4);
    return;                              // besonderes return in main
}

Godbolt Listing lst-0192-godb.cpp, https://godbolt.org/z/5ddxa9v1j:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5ddxa9v1j 
#include <iostream>                      // cout
int min3(int x, int y, int z) {          // Funktion liefert einen int zurück
    if(x<y) {
        if(x<z) return x;
        else return z;
    } else if(y<z) {
        return y;
    }
    else return z;
}
void printMin(int x, int y, int z) {     // Funktion liefert nichts zurück
    if(x<0 || y<0 || z<0) {
        std::cout << "Bitte nur Zahlen groesser 0\n";
        return;
    }
    std::cout << min3(x,y,z) << "\n";
}                                        // hier steht kein return
int main() {
    printMin(3, -4, 8);
    printMin(6, 77, 4);
    return;                              // besonderes return in main
}

Listing 8.22: Vermeiden Sie goto-Anweisungen.

Book listing lst-0193-book.cpp:

// https://godbolt.org/z/ohd5Pr8fb 
#include <iostream>
int main() {
    int idx = 4;
    goto mehr;                      // springe zu Label mehr
  drucke:                           // Label für die nächste Anweisung
    std::cout << idx << std::endl;
    idx = idx * 2;
  mehr:
    idx = idx + 3;
    if(idx < 20)
        goto drucke;                // goto kann auch in einem if stehen
  ende:                             // dies ist ein Label, wird aber nicht verwendet
    return 0;
}

Godbolt Listing lst-0193-godb.cpp, https://godbolt.org/z/ohd5Pr8fb:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ohd5Pr8fb 
#include <iostream>
int main() {
    int idx = 4;
    goto mehr;                      // springe zu Label mehr
  drucke:                           // Label für die nächste Anweisung
    std::cout << idx << std::endl;
    idx = idx * 2;
  mehr:
    idx = idx + 3;
    if(idx < 20)
        goto drucke;                // goto kann auch in einem if stehen
  ende:                             // dies ist ein Label, wird aber nicht verwendet
    return 0;
}

Listing 8.23: Eine Funktion weniger, aber ein Label und zwei »goto«-Anweisungen mehr.

Book listing lst-0194-book.cpp:

// https://godbolt.org/z/b361eeba3 
// #includes, prims, eingabeBis(), ausgabePrims() und main() wie zuvor 
std::vector<int> prims{2};
void berechnePrimsBis(int bis) {
    /* Prims-Berechnung */
    /* vector muss an dieser Stelle {2} enthalten */
    for(int n=3; n<bis; n=n+2) {
        for(int teil: prims) {
            if(teil*teil > n)
                goto prim;     // mit goto, weil ein break …
            if(n%teil==0)
                goto nichtPrim;// … über zwei Schleifen nicht geht.
        }
      prim: ;                  // Ziel des Sprungs vor push_back
        prims.push_back(n);    // n ist prim! Merken als Teiler und Ergebnis
      nichtPrim: ;             // Ziel des Sprungs hinter push_back
    }
}

Godbolt Listing lst-0194-godb.cpp, https://godbolt.org/z/b361eeba3:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/b361eeba3 
// #includes, prims, eingabeBis(), ausgabePrims() und main() wie zuvor 
std::vector<int> prims{2};
void berechnePrimsBis(int bis) {
    /* Prims-Berechnung */
    /* vector muss an dieser Stelle {2} enthalten */
    for(int n=3; n<bis; n=n+2) {
        for(int teil: prims) {
            if(teil*teil > n)
                goto prim;     // mit goto, weil ein break …
            if(n%teil==0)
                goto nichtPrim;// … über zwei Schleifen nicht geht.
        }
      prim: ;                  // Ziel des Sprungs vor push_back
        prims.push_back(n);    // n ist prim! Merken als Teiler und Ergebnis
      nichtPrim: ;             // Ziel des Sprungs hinter push_back
    }
}

Listing 8.24: Als Ausblick hier Ihre erste Exception-Behandlung mit »try« und »catch«

Book listing lst-0195-book.cpp:

// https://godbolt.org/z/cjfG7bc33 
#include <iostream>
int main() {
    try {                                       // Beginn des try-Blocks
        for(int n=1; ; n=n*2) {
            if(n < 0) {
                throw "Es gab einen Ueberlauf";  // Fehler auslösen
            }
        }
    }                                            // Ende des try-Blocks
    catch(const char *fehler) {                  // falls dieser Fehler auftritt, …
      std::cout << "Fehler: " << fehler << "\n"; // … behandle ihn so
    }
}

Godbolt Listing lst-0195-godb.cpp, https://godbolt.org/z/cjfG7bc33:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cjfG7bc33 
#include <iostream>
int main() {
    try {                                       // Beginn des try-Blocks
        for(int n=1; ; n=n*2) {
            if(n < 0) {
                throw "Es gab einen Ueberlauf";  // Fehler auslösen
            }
        }
    }                                            // Ende des try-Blocks
    catch(const char *fehler) {                  // falls dieser Fehler auftritt, …
      std::cout << "Fehler: " << fehler << "\n"; // … behandle ihn so
    }
}

Listing 9.1: Typen von Ausdrücken sind wichtig, weil damit entschieden wird, wie es weitergeht.

Book listing lst-0196-book.cpp:

// https://godbolt.org/z/E1aGdox6q 
#include <iostream>           // cout
#include <string>
void drucke(int n) {          // Funktion drucke für Typ int
    std::cout << "Zahl:" << n << "\n";
}
void drucke(std::string s) {  // gleicher Name, anderer Typ
    std::cout << "Zeichenkette:" << s << "\n";
}
int main() {
    int zahl = 10;
    std::string name = "Bilbo";
    drucke(zahl);              // ruft drucke(int) auf, zahl ist int
    drucke(name);              // ruft drucke(string) auf, name ist string
    drucke(11 + 22);           // Ausdruck ist int
    drucke(name + " Baggins"); // Ausdruck ist string
}

Godbolt Listing lst-0196-godb.cpp, https://godbolt.org/z/E1aGdox6q:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/E1aGdox6q 
#include <iostream>           // cout
#include <string>
void drucke(int n) {          // Funktion drucke für Typ int
    std::cout << "Zahl:" << n << "\n";
}
void drucke(std::string s) {  // gleicher Name, anderer Typ
    std::cout << "Zeichenkette:" << s << "\n";
}
int main() {
    int zahl = 10;
    std::string name = "Bilbo";
    drucke(zahl);              // ruft drucke(int) auf, zahl ist int
    drucke(name);              // ruft drucke(string) auf, name ist string
    drucke(11 + 22);           // Ausdruck ist int
    drucke(name + " Baggins"); // Ausdruck ist string
}

GodboltId:EY5K6Wsr3

Book listing lst-0203-book.cpp:

// https://godbolt.org/z/EY5K6Wsr3 
std::vector<int> data(10);     // 10 mal 0 in einem vector
data.front() = 666;            // schreibt 666 an die vorderste Stelle

Godbolt Listing lst-0203-godb.cpp, https://godbolt.org/z/EY5K6Wsr3:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/EY5K6Wsr3 
std::vector<int> data(10);     // 10 mal 0 in einem vector
data.front() = 666;            // schreibt 666 an die vorderste Stelle

GodboltId:K9c913had

Book listing lst-0204-book.cpp:

// https://godbolt.org/z/K9c913had 
if(int result;  (result = read(buffer, 100)) != 0) {
    std::cerr << "Es trat Fehler Nummer "<< result << " auf.\n";
}

Godbolt Listing lst-0204-godb.cpp, https://godbolt.org/z/K9c913had:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/K9c913had 
if(int result;  (result = read(buffer, 100)) != 0) {
    std::cerr << "Es trat Fehler Nummer "<< result << " auf.\n";
}

Listing 10.1: Reagieren Sie auf viele Zustände mit Rückgabewerten unterschiedlicher Art.

Book listing lst-0210-book.cpp:

// https://godbolt.org/z/K37fMW8fE 
#include <iostream> // cout, cerr
#include <fstream>
#include <vector>
#include <string>
using std::vector; using std::string; using std::cout; using std::cerr;

int zaehleWoerter(const string& filename) { // Rückgabe kleiner 0 bei Fehler
    std::ifstream file{filename};
    if(!file) {     // Gab es einen Fehler beim Öffnen der Datei?
        cerr << "Fehler beim Oeffnen von " << filename << "\n";
        return -1;  // dem Aufrufer einen Fehler mittels besonderem Wert melden
    }
    int count = 0;
    string wort;
    while(!file.eof()) {    // noch nicht am Ende?
        file >> wort;
        ++count;
    }
    return count-1;         // –1: am EOF wurde noch ein Wort gelesen
}
bool process(const vector<string>& args) { // Rückgabe true bei alles okay
    if(args.size() == 0) {  // erwarten Parameter
        cerr << "Kommandozeilenargument fehlt\n";
        return false;       // mittels Rückgabe einen Fehler mitteilen
    } else {
        bool result = true; // fürs Endergebnis
        for(const string filename : args) {
            cout << filename << ": ";
            int count = zaehleWoerter(filename);
            if(count < 0) { // besondere Rückgabe zeigt Fehler an
                cout << "Fehler!\n";
                result = false;         // mindestens ein Fehler
            } else {
                cout << count << "\n";  // normales Ergebnis ausgeben
            }
        }
        return result;                  // Gesamtergebnis zurückgeben
    }
}

int main(int argc, const char* argv[]) {
    bool result = process(              // Rückgabewert enthält Fehlerindikator
        {argv+1, argv+argc} );          // const char*[] nach vector<string>
    if(result) {                        // Rückgabewert auswerten
        return 0;
    } else {
        cerr << "Es trat ein Fehler auf.\n";
        return 1;   // außen Fehler anzeigen
    }
}

Godbolt Listing lst-0210-godb.cpp, https://godbolt.org/z/K37fMW8fE:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/K37fMW8fE 
#include <iostream> // cout, cerr
#include <fstream>
#include <vector>
#include <string>
using std::vector; using std::string; using std::cout; using std::cerr;

int zaehleWoerter(const string& filename) { // Rückgabe kleiner 0 bei Fehler
    std::ifstream file{filename};
    if(!file) {     // Gab es einen Fehler beim Öffnen der Datei?
        cerr << "Fehler beim Oeffnen von " << filename << "\n";
        return -1;  // dem Aufrufer einen Fehler mittels besonderem Wert melden
    }
    int count = 0;
    string wort;
    while(!file.eof()) {    // noch nicht am Ende?
        file >> wort;
        ++count;
    }
    return count-1;         // –1: am EOF wurde noch ein Wort gelesen
}
bool process(const vector<string>& args) { // Rückgabe true bei alles okay
    if(args.size() == 0) {  // erwarten Parameter
        cerr << "Kommandozeilenargument fehlt\n";
        return false;       // mittels Rückgabe einen Fehler mitteilen
    } else {
        bool result = true; // fürs Endergebnis
        for(const string filename : args) {
            cout << filename << ": ";
            int count = zaehleWoerter(filename);
            if(count < 0) { // besondere Rückgabe zeigt Fehler an
                cout << "Fehler!\n";
                result = false;         // mindestens ein Fehler
            } else {
                cout << count << "\n";  // normales Ergebnis ausgeben
            }
        }
        return result;                  // Gesamtergebnis zurückgeben
    }
}

int main(int argc, const char* argv[]) {
    bool result = process(              // Rückgabewert enthält Fehlerindikator
        {argv+1, argv+argc} );          // const char*[] nach vector<string>
    if(result) {                        // Rückgabewert auswerten
        return 0;
    } else {
        cerr << "Es trat ein Fehler auf.\n";
        return 1;   // außen Fehler anzeigen
    }
}

Listing 10.2: Exceptions werden mit »throw« ausgelöst und mit »try-catch« behandelt.

Book listing lst-0211-book.cpp:

// https://godbolt.org/z/sz9hxKozf 
#include <iostream>            // cout, cerr
#include <vector>
#include <string>
#include <fstream>             // ifstream
#include <stdexcept>           // invalid_argument
using std::vector; using std::string; using std::cout; using std::ifstream;
size_t zaehleWoerter(const string& filename) { // 0 oder größer
    std::ifstream file{};      // ungeöffnet erzeugen
    // anmelden für Exceptions:
    file.exceptions(ifstream::failbit | ifstream::badbit);
    file.open(filename);       // könnte eine Exception auslösen
    size_t count = 0;
    string wort;
    file.exceptions(ifstream::badbit); // EOF keine Exception mehr
    while(!file.eof()) {       // noch nicht am Ende?
        file >> wort;   ++count;
    }
    return count-1;            // –1: am EOF wurde noch ein Wort gelesen
}
void process(const vector<string>& args) {
    if(args.size() == 0) {     // process erwartet Parameter
        throw std::invalid_argument{"Kommandozeilenarg. fehlt"}; // auslösen
    } else {
        for(const string filename : args) {
            cout << filename << ": " << zaehleWoerter(filename) << std::endl;
        }
    }
}
int main(int argc, const char* argv[]) {
    try {                                      // Block mit Fehlerbehandlungen
        process(
          vector<string>{argv+1, argv+argc} ); // const char*[] nach vector<string>
        return 0;
    } catch(std::exception &exc) {  // Fehlerbehandlung
        std::cerr << "Es trat ein Fehler auf: " << exc.what() << "\n";
        return 1;
    }
}

Godbolt Listing lst-0211-godb.cpp, https://godbolt.org/z/sz9hxKozf:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sz9hxKozf 
#include <iostream>            // cout, cerr
#include <vector>
#include <string>
#include <fstream>             // ifstream
#include <stdexcept>           // invalid_argument
using std::vector; using std::string; using std::cout; using std::ifstream;
size_t zaehleWoerter(const string& filename) { // 0 oder größer
    std::ifstream file{};      // ungeöffnet erzeugen
    // anmelden für Exceptions:
    file.exceptions(ifstream::failbit | ifstream::badbit);
    file.open(filename);       // könnte eine Exception auslösen
    size_t count = 0;
    string wort;
    file.exceptions(ifstream::badbit); // EOF keine Exception mehr
    while(!file.eof()) {       // noch nicht am Ende?
        file >> wort;   ++count;
    }
    return count-1;            // –1: am EOF wurde noch ein Wort gelesen
}
void process(const vector<string>& args) {
    if(args.size() == 0) {     // process erwartet Parameter
        throw std::invalid_argument{"Kommandozeilenarg. fehlt"}; // auslösen
    } else {
        for(const string filename : args) {
            cout << filename << ": " << zaehleWoerter(filename) << std::endl;
        }
    }
}
int main(int argc, const char* argv[]) {
    try {                                      // Block mit Fehlerbehandlungen
        process(
          vector<string>{argv+1, argv+argc} ); // const char*[] nach vector<string>
        return 0;
    } catch(std::exception &exc) {  // Fehlerbehandlung
        std::cerr << "Es trat ein Fehler auf: " << exc.what() << "\n";
        return 1;
    }
}

Listing 10.3: Ein »catch« kann auch innerhalb einer Schleife stehen.

Book listing lst-0212-book.cpp:

void process(const vector<string>& args) {
    if(args.size() == 0) {                 // erwarte Parameter
        throw std::invalid_argument{"Kommandozeilenargument fehlt"};
    } else {
        for(const string filename : args) {
            cout << filename << ": ";
            try {
                cout << zaehleWoerter(filename) << "\n";
            } catch(std::exception &exc) {
                cout << "Fehler: " << exc.what() << "\n";
            }
        }
    }
}

Listing 10.4: Mit »throw« ohne Parameter werfen Sie die gerade behandelte Ausnahme weiter.

Book listing lst-0213-book.cpp:

try {
    cout << zaehleWoerter(filename) << "\n";
} catch(std::exception &exc) {
    cout << "Fehler: " << exc.what() << "\n";
    throw; // weiterwerfen
}

Listing 10.5: Sie können auch andere Typen als Ausnahme auslösen.

Book listing lst-0215-book.cpp:

// https://godbolt.org/z/67cd5bhhE 
#include <string>
#include <iostream> // cout
using std::string; using std::to_string; using std::cout;
void fehlerAusloesen(int fehlerfall) {
   try {
       if(fehlerfall < 10) throw (int)fehlerfall;
       else if(fehlerfall < 20) throw 1.0/(fehlerfall-10.0);
       else throw string{"Fehler " + to_string(fehlerfall)};
   } catch(int eval) {
       cout << "int-fehler: " << eval << "\n";
   } catch(double eval) {
       cout << "double-fehler: " << eval << "\n";
   } catch(string eval) {
       cout << "string-fehler: " << eval << "\n";
   }
}
int main() {
    fehlerAusloesen(3);  // int-fehler: 3
    fehlerAusloesen(14); // Ausgabe: double-fehler: 0.25
    fehlerAusloesen(50); // Ausgabe: string-fehler: Fehler 50
}

Godbolt Listing lst-0215-godb.cpp, https://godbolt.org/z/67cd5bhhE:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/67cd5bhhE 
#include <string>
#include <iostream> // cout
using std::string; using std::to_string; using std::cout;
void fehlerAusloesen(int fehlerfall) {
   try {
       if(fehlerfall < 10) throw (int)fehlerfall;
       else if(fehlerfall < 20) throw 1.0/(fehlerfall-10.0);
       else throw string{"Fehler " + to_string(fehlerfall)};
   } catch(int eval) {
       cout << "int-fehler: " << eval << "\n";
   } catch(double eval) {
       cout << "double-fehler: " << eval << "\n";
   } catch(string eval) {
       cout << "string-fehler: " << eval << "\n";
   }
}
int main() {
    fehlerAusloesen(3);  // int-fehler: 3
    fehlerAusloesen(14); // Ausgabe: double-fehler: 0.25
    fehlerAusloesen(50); // Ausgabe: string-fehler: Fehler 50
}

Listing 10.6: Lassen Sie sich wenigstens den Fehlertyp und -text ausgeben, anstatt Ihr Programm aus »main« herauspurzeln zu lassen.

Book listing lst-0216-book.cpp:

// https://godbolt.org/z/TsP33njar 
#include <iostream>
#include <stdexcept> // exception

int main() {
    try {
        // … Ihr sonstiger Code …
    } catch(std::exception& exc) {
        std::cerr << "main: " << exc.what() << "\n";
    }
}

Godbolt Listing lst-0216-godb.cpp, https://godbolt.org/z/TsP33njar:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TsP33njar 
#include <iostream>
#include <stdexcept> // exception

int main() {
    try {
        // … Ihr sonstiger Code …
    } catch(std::exception& exc) {
        std::cerr << "main: " << exc.what() << "\n";
    }
}

Listing 11.1: Die Haupt-Headerdatei der Bibliothek qwort.hpp

Book listing lst-0217-book.cpp:

// https://godbolt.org/z/7nasGjGq6 
#ifndef QWORT_H // Header-Guard
#define QWORT_H
#include <string>
#include <memory> // unique_ptr
namespace qw { // Namensraum der Bibliothek
    int version();
    namespace impl_multimap {
        class index_impl;
    }
    class index {
        using index_impl = impl_multimap::index_impl;
    public:
        index();
        ~index() noexcept; // wird für pimpl benötigt
        index(const index&) = default;
        index(index&&) noexcept;
        index& operator=(const index&) = default;
        index& operator=(index&&) = default;
    public:
        void add(const std::string &arg);
        size_t size() const;
        std::string getBestMatch(const std::string& query) const;
    public:          // public für Tests
        std::string normalize(std::string arg) const;
    private:
        const std::unique_ptr<index_impl> pimpl;
    };
} // namespace qw
#endif // Header-Guard

Godbolt Listing lst-0217-godb.cpp, https://godbolt.org/z/7nasGjGq6:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7nasGjGq6 
#ifndef QWORT_H // Header-Guard
#define QWORT_H
#include <string>
#include <memory> // unique_ptr
namespace qw { // Namensraum der Bibliothek
    int version();
    namespace impl_multimap {
        class index_impl;
    }
    class index {
        using index_impl = impl_multimap::index_impl;
    public:
        index();
        ~index() noexcept; // wird für pimpl benötigt
        index(const index&) = default;
        index(index&&) noexcept;
        index& operator=(const index&) = default;
        index& operator=(index&&) = default;
    public:
        void add(const std::string &arg);
        size_t size() const;
        std::string getBestMatch(const std::string& query) const;
    public:          // public für Tests
        std::string normalize(std::string arg) const;
    private:
        const std::unique_ptr<index_impl> pimpl;
    };
} // namespace qw
#endif // Header-Guard

Listing 11.2: Die Schnittstellenklasse leitet alle Aufrufe an die Implementierungsklasse weiter.

Book listing lst-0218-book.cpp:

// https://godbolt.org/z/zbcdd1jha 
#include "qwort/qwort.hpp" // selbst
#include <map>
#include <algorithm>       // transform
#include <cctype>          // toupper
#include "impl_multimap.hpp"
using std::map; using std::string;

namespace qw {
    int version() {
        return 1;
    }
    // Verwaltung
    index::index()
        : pimpl{ new index_impl{} }
        { }
    index::~index() noexcept = default;
    index::index(index&&) noexcept = default;
    // Schnittstelle
    void index::add(const string &arg) {
        pimpl->add(normalize(arg), arg);
    }
    size_t index::size() const {
        return pimpl->size();
    }
    string index::getBestMatch(const string& query) const {
        return pimpl->getBestMatch(normalize(query));
    }
    string index::normalize(string str) const {
        using namespace std; // begin, end
        transform(begin(str), end(str), begin(str), [](char c) {
                return ::isalpha(c) ? ::toupper(c) : '#';
            });
        return str;
    }
} // namespace qw

Godbolt Listing lst-0218-godb.cpp, https://godbolt.org/z/zbcdd1jha:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zbcdd1jha 
#include "qwort/qwort.hpp" // selbst
#include <map>
#include <algorithm>       // transform
#include <cctype>          // toupper
#include "impl_multimap.hpp"
using std::map; using std::string;

namespace qw {
    int version() {
        return 1;
    }
    // Verwaltung
    index::index()
        : pimpl{ new index_impl{} }
        { }
    index::~index() noexcept = default;
    index::index(index&&) noexcept = default;
    // Schnittstelle
    void index::add(const string &arg) {
        pimpl->add(normalize(arg), arg);
    }
    size_t index::size() const {
        return pimpl->size();
    }
    string index::getBestMatch(const string& query) const {
        return pimpl->getBestMatch(normalize(query));
    }
    string index::normalize(string str) const {
        using namespace std; // begin, end
        transform(begin(str), end(str), begin(str), [](char c) {
                return ::isalpha(c) ? ::toupper(c) : '#';
            });
        return str;
    }
} // namespace qw

Listing 11.3: Header der Implementierungsklasse

Book listing lst-0219-book.cpp:

// https://godbolt.org/z/5Tfr6xxa5 
#include <string>
#include <string_view>
#include <vector>
#include <map> // multimap
namespace qw::impl_multimap {
using std::vector; using std::multimap; 
using std::string; using std::string_view;
class index_impl {
    vector<string> entries;
    multimap<string,size_t> qindex;
public:
    void add(string_view normalized, string_view original);
    string getBestMatch(string_view normalized) const;
    size_t size() const {
        return entries.size();
    }
private:
    vector<string> qgramify(string_view normalized) const;
    static constexpr size_t Q = 3;
    static const std::string PREFIX;
    static const std::string SUFFIX;
public: // test interface
    vector<string> _qgramify(string_view n) const { return qgramify(n); }
    static size_t _q() { return Q; }
    static std::string _prefix() { return PREFIX; }
    static std::string _suffix() { return SUFFIX; }
};
} // namespace qw::impl_multimap

Godbolt Listing lst-0219-godb.cpp, https://godbolt.org/z/5Tfr6xxa5:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5Tfr6xxa5 
#include <string>
#include <string_view>
#include <vector>
#include <map> // multimap
namespace qw::impl_multimap {
using std::vector; using std::multimap; 
using std::string; using std::string_view;
class index_impl {
    vector<string> entries;
    multimap<string,size_t> qindex;
public:
    void add(string_view normalized, string_view original);
    string getBestMatch(string_view normalized) const;
    size_t size() const {
        return entries.size();
    }
private:
    vector<string> qgramify(string_view normalized) const;
    static constexpr size_t Q = 3;
    static const std::string PREFIX;
    static const std::string SUFFIX;
public: // test interface
    vector<string> _qgramify(string_view n) const { return qgramify(n); }
    static size_t _q() { return Q; }
    static std::string _prefix() { return PREFIX; }
    static std::string _suffix() { return SUFFIX; }
};
} // namespace qw::impl_multimap

Listing 11.4: Der Header der Implementierungsklasse

Book listing lst-0220-book.cpp:

// https://godbolt.org/z/41sPszG1G 
#include "impl_multimap.hpp" // Header zu dieser Datei
#include <map>
#include <string>
#include <string_view>

namespace qw::impl_multimap {

using std::vector; using std::multimap; using std::map; using std::string;
using std::string_view; using namespace std::literals::string_literals;

void index_impl::add(string_view normalized, string_view original) {
    /* TODO: Vorhandensein in 'entries' prüfen */
    const auto pos = entries.size(); // Index des neuen Eintrags
    entries.push_back(string(original));
    auto qgrams = qgramify(normalized);
    for(const auto& qgram : qgrams) {
        qindex.insert( make_pair(qgram, pos) );
    }
}
string index_impl::getBestMatch(string_view normalized) const {
    auto qgrams = qgramify(normalized);
    /* hits speichert, welche Wörter wie oft getroffen wurden */
    map<size_t, size_t> hits; /* 'entries-index' zu 'hit-count' */
    size_t maxhits = 0z; /* immer: max(hits.second) */
    for(const auto& qgram : qgrams) {
        auto [beg, end] = qindex.equal_range(qgram);
        for(auto it=beg; it!=end; ++it) {
            hits[it->second] += 1z; /* hit-count des Eintrags */
            if(hits[it->second] > maxhits) { /* max-Suche einfacher */
                maxhits = hits[it->second];
            }
        }
    }
    /* Suche ersten Eintrag mit maxhits. Bessere Implementierung mit PrioQueue möglich */
    for(auto const &hit : hits) {
        if(hit.second == maxhits) {
            return entries[hit.first];
        }
    }
    /* nur erreicht, wenn entries leer ist */
    return ""s;
}
const string index_impl::PREFIX = string(Q-1, '^');
const string index_impl::SUFFIX = string(Q-1, '$');

vector<string> index_impl::qgramify(string_view normalized) const {
    auto word = PREFIX + string(normalized)+SUFFIX; /* Trick für bessere QGramme */
    vector<string> result {};
    auto left = word.cbegin();
    auto right = std::next(word.cbegin(), Q); /* okay: |"^^"|+|"$$"| => 3 */
    for( ; right <= word.end(); ++left, ++right) {
        result.emplace_back(left, right);
    }
    return result;
}
} // namespace qw::impl_multimap

Godbolt Listing lst-0220-godb.cpp, https://godbolt.org/z/41sPszG1G:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/41sPszG1G 
#include "impl_multimap.hpp" // Header zu dieser Datei
#include <map>
#include <string>
#include <string_view>

namespace qw::impl_multimap {

using std::vector; using std::multimap; using std::map; using std::string;
using std::string_view; using namespace std::literals::string_literals;

void index_impl::add(string_view normalized, string_view original) {
    /* TODO: Vorhandensein in 'entries' prüfen */
    const auto pos = entries.size(); // Index des neuen Eintrags
    entries.push_back(string(original));
    auto qgrams = qgramify(normalized);
    for(const auto& qgram : qgrams) {
        qindex.insert( make_pair(qgram, pos) );
    }
}
string index_impl::getBestMatch(string_view normalized) const {
    auto qgrams = qgramify(normalized);
    /* hits speichert, welche Wörter wie oft getroffen wurden */
    map<size_t, size_t> hits; /* 'entries-index' zu 'hit-count' */
    size_t maxhits = 0z; /* immer: max(hits.second) */
    for(const auto& qgram : qgrams) {
        auto [beg, end] = qindex.equal_range(qgram);
        for(auto it=beg; it!=end; ++it) {
            hits[it->second] += 1z; /* hit-count des Eintrags */
            if(hits[it->second] > maxhits) { /* max-Suche einfacher */
                maxhits = hits[it->second];
            }
        }
    }
    /* Suche ersten Eintrag mit maxhits. Bessere Implementierung mit PrioQueue möglich */
    for(auto const &hit : hits) {
        if(hit.second == maxhits) {
            return entries[hit.first];
        }
    }
    /* nur erreicht, wenn entries leer ist */
    return ""s;
}
const string index_impl::PREFIX = string(Q-1, '^');
const string index_impl::SUFFIX = string(Q-1, '$');

vector<string> index_impl::qgramify(string_view normalized) const {
    auto word = PREFIX + string(normalized)+SUFFIX; /* Trick für bessere QGramme */
    vector<string> result {};
    auto left = word.cbegin();
    auto right = std::next(word.cbegin(), Q); /* okay: |"^^"|+|"$$"| => 3 */
    for( ; right <= word.end(); ++left, ++right) {
        result.emplace_back(left, right);
    }
    return result;
}
} // namespace qw::impl_multimap

Listing 11.5: So ziemlich das einfachste Beispielprogramm der Bibliothek

Book listing lst-0221-book.cpp:

// https://godbolt.org/z/Gvcj6hhYf 
#include <cstdlib>  // EXIT_SUCCESS
#include <iostream> // cout
#include <vector>
#include <string>
#include "qwort/qwort.hpp"
using std::cout; using std::vector; using std::string;
int main(int argc, const char* argv[]) {
    cout << "qwort version " << qw::version() << "\n";

    /* Index bauen */
    qw::index myindex{};

    /* - Demodaten */
    myindex.add("Deutschland");
    myindex.add("Griechenland");

    /* Abfragen erzeugen */
    vector<string> args(argv+1, argv+argc); // iteratorbasierte Initialisierung
    for(auto &querystring : args) {
        cout << "Suche '" << querystring << "'... ";
        const auto match = myindex.getBestMatch(querystring);
        cout << match << "\n";
    }
    return EXIT_SUCCESS;
}

Godbolt Listing lst-0221-godb.cpp, https://godbolt.org/z/Gvcj6hhYf:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Gvcj6hhYf 
#include <cstdlib>  // EXIT_SUCCESS
#include <iostream> // cout
#include <vector>
#include <string>
#include "qwort/qwort.hpp"
using std::cout; using std::vector; using std::string;
int main(int argc, const char* argv[]) {
    cout << "qwort version " << qw::version() << "\n";

    /* Index bauen */
    qw::index myindex{};

    /* - Demodaten */
    myindex.add("Deutschland");
    myindex.add("Griechenland");

    /* Abfragen erzeugen */
    vector<string> args(argv+1, argv+argc); // iteratorbasierte Initialisierung
    for(auto &querystring : args) {
        cout << "Suche '" << querystring << "'... ";
        const auto match = myindex.getBestMatch(querystring);
        cout << match << "\n";
    }
    return EXIT_SUCCESS;
}

Listing 12.1: Listing 12.1 Einen eigenen Datentyp erzeugen Sie mit »struct«.

Book listing lst-0222-book.cpp:

// https://godbolt.org/z/8YqoTEx58 
#include <string>
#include <iostream>                     // cout
#include <format>
using std::string; using std::cout; using std::format;
struct Person {                         // definiert den neuen Typ Person
    string name_;
    int alter_;
    string ort_;
};                                      // abschließendes Semikolon
void drucke(Person p) {                 // ganze Person als ein Parameter
    cout << format("{} ({}) aus {}\n",
      p.name_, p.alter_, p.ort_);       // Zugriff per Punkt
}
int main() {
    Person otto {"Otto", 45, "Kassel" }; // Initialisierung
    drucke(otto);                        // Aufruf als Einheit
}

Godbolt Listing lst-0222-godb.cpp, https://godbolt.org/z/8YqoTEx58:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8YqoTEx58 
#include <string>
#include <iostream>                     // cout
#include <format>
using std::string; using std::cout; using std::format;
struct Person {                         // definiert den neuen Typ Person
    string name_;
    int alter_;
    string ort_;
};                                      // abschließendes Semikolon
void drucke(Person p) {                 // ganze Person als ein Parameter
    cout << format("{} ({}) aus {}\n",
      p.name_, p.alter_, p.ort_);       // Zugriff per Punkt
}
int main() {
    Person otto {"Otto", 45, "Kassel" }; // Initialisierung
    drucke(otto);                        // Aufruf als Einheit
}

Listing 12.2: Listing 12.2 Die Deklaration einer Klasse nennt erst mal nur ihren Namen, die Definition enthält alle ihre Elemente.

Book listing lst-0223-book.cpp:

// https://godbolt.org/z/jPqn7c3T8 
#include <memory>                      // shared_ptr
#include <vector>                      // vector
struct Mitarbeiter;                    // Klassendeklaration
struct Chef;                           // Klassendeklaration
struct Mitarbeiter {                   // Klassendefinition
    std::shared_ptr<Chef> chef_;       // Zeiger auf Chef
    void print() const;                // Methodendeklaration
};
struct Chef {                           // Definition
    std::vector<std::shared_ptr<Mitarbeiter>> mitarbeiter_; // Zeiger auf Mitarbeiter
    void print() const;                 // Methodendeklaration
};
void Mitarbeiter::print() const {       // Methodendefinition
    // …
}
void Chef::print() const {              // Methodendefinition
    // …
}

Godbolt Listing lst-0223-godb.cpp, https://godbolt.org/z/jPqn7c3T8:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jPqn7c3T8 
#include <memory>                      // shared_ptr
#include <vector>                      // vector
struct Mitarbeiter;                    // Klassendeklaration
struct Chef;                           // Klassendeklaration
struct Mitarbeiter {                   // Klassendefinition
    std::shared_ptr<Chef> chef_;       // Zeiger auf Chef
    void print() const;                // Methodendeklaration
};
struct Chef {                           // Definition
    std::vector<std::shared_ptr<Mitarbeiter>> mitarbeiter_; // Zeiger auf Mitarbeiter
    void print() const;                 // Methodendeklaration
};
void Mitarbeiter::print() const {       // Methodendefinition
    // …
}
void Chef::print() const {              // Methodendefinition
    // …
}

Listing 12.3: Listing 12.3 Mit designierten Initialisierern geben Sie die zu setzenden Elemente an.

Book listing lst-0226-book.cpp:

// https://godbolt.org/z/e9Wshbx3q 
Person otto1 {"Otto", 45, "Kassel" }; // korrekt
Person otto2 {"Kassel", 45, "Otto" }; // oje, vertauscht, und keiner merkt's
Person hans { .name_ = "Hans", .alter_ = 23, .ort_ = "Berlin" }; // okay
Person willi { .name_ = "Willi", .alter_ = 48  }; // okay, nicht alle angegeben
Person karl { "Karl", .alter_ = 53  }; //             (ERR)  alle designiert oder keiner
Person paul { .alter_ = 34, .name_ = "Paul", .ort = "Bonn" }; //             (ERR)  vertauscht
Person pit(.name_="Pit", .alter_=34, .ort_="Wyk"); //             (ERR)  nicht mit runden Klammern

Godbolt Listing lst-0226-godb.cpp, https://godbolt.org/z/e9Wshbx3q:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/e9Wshbx3q 
Person otto1 {"Otto", 45, "Kassel" }; // korrekt
Person otto2 {"Kassel", 45, "Otto" }; // oje, vertauscht, und keiner merkt's
Person hans { .name_ = "Hans", .alter_ = 23, .ort_ = "Berlin" }; // okay
Person willi { .name_ = "Willi", .alter_ = 48  }; // okay, nicht alle angegeben
Person karl { "Karl", .alter_ = 53  }; //             (ERR)  alle designiert oder keiner
Person paul { .alter_ = 34, .name_ = "Paul", .ort = "Bonn" }; //             (ERR)  vertauscht
Person pit(.name_="Pit", .alter_=34, .ort_="Wyk"); //             (ERR)  nicht mit runden Klammern

GodboltId:xnT7voqen

Book listing lst-0227-book.cpp:

// https://godbolt.org/z/xnT7voqen 
// Ausschnitt
Person erzeuge(string name, int alter, string ort) { // Rückgabetyp
    Person result {name, alter, ort};
    return result;
}
int main() {
    Person otto = erzeuge("Otto", 45, "Kassel"); // Rückgabe speichern
    drucke(otto);
}

Godbolt Listing lst-0227-godb.cpp, https://godbolt.org/z/xnT7voqen:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xnT7voqen 
// Ausschnitt
Person erzeuge(string name, int alter, string ort) { // Rückgabetyp
    Person result {name, alter, ort};
    return result;
}
int main() {
    Person otto = erzeuge("Otto", 45, "Kassel"); // Rückgabe speichern
    drucke(otto);
}

GodboltId:YYfxMdfP8

Book listing lst-0228-book.cpp:

// https://godbolt.org/z/YYfxMdfP8 
Person erzeuge(string name, int alter, string ort) {
    return Person{name, alter, ort};       // direkt zurückgegeben
}
int main() {
    drucke(erzeuge("Otto", 45, "Kassel")); // Rückgabe direkt verwendet
}

Godbolt Listing lst-0228-godb.cpp, https://godbolt.org/z/YYfxMdfP8:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YYfxMdfP8 
Person erzeuge(string name, int alter, string ort) {
    return Person{name, alter, ort};       // direkt zurückgegeben
}
int main() {
    drucke(erzeuge("Otto", 45, "Kassel")); // Rückgabe direkt verwendet
}

Listing 12.4: Listing 12.4 Hier ist die Angabe von Person beim return nötig.

Book listing lst-0231-book.cpp:

// https://godbolt.org/z/KvTx3rPs5 
auto erzeuge(string name, int alter, string ort) {
    return Person{name, alter, ort};  // auto verlangt Konstruktornamen
}
auto erzeuge2(string name, int alter, string ort) {
    return {name, alter, ort};       //             (ERR)  auto mit initializer_list geht nicht
}

Godbolt Listing lst-0231-godb.cpp, https://godbolt.org/z/KvTx3rPs5:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KvTx3rPs5 
auto erzeuge(string name, int alter, string ort) {
    return Person{name, alter, ort};  // auto verlangt Konstruktornamen
}
auto erzeuge2(string name, int alter, string ort) {
    return {name, alter, ort};       //             (ERR)  auto mit initializer_list geht nicht
}

Listing 12.5: Listing 12.5 Methoden packen Daten und Verhalten zusammen.

Book listing lst-0232-book.cpp:

// https://godbolt.org/z/M1ozTorEz 
#include <string>
#include <iostream>
#include <format>
using std::string; using std::cout; using std::format;
struct Person {
  string name_;
  int alter_;
  string ort_;
  void drucke();            // Funktion als Methode des Typs
};
void Person::drucke() {     // Name der Methode wird um Person:: erweitert
  cout << format("{} ({}) aus {}\n",
    name_, alter_, ort_);   // in einer Methode können Sie direkt auf Felder zugreifen
}
int main() {
  Person otto {"Otto", 45, "Kassel" };
  otto.drucke();            // Aufruf der Methode für eine Variable des Typs
}

Godbolt Listing lst-0232-godb.cpp, https://godbolt.org/z/M1ozTorEz:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M1ozTorEz 
#include <string>
#include <iostream>
#include <format>
using std::string; using std::cout; using std::format;
struct Person {
  string name_;
  int alter_;
  string ort_;
  void drucke();            // Funktion als Methode des Typs
};
void Person::drucke() {     // Name der Methode wird um Person:: erweitert
  cout << format("{} ({}) aus {}\n",
    name_, alter_, ort_);   // in einer Methode können Sie direkt auf Felder zugreifen
}
int main() {
  Person otto {"Otto", 45, "Kassel" };
  otto.drucke();            // Aufruf der Methode für eine Variable des Typs
}

Listing 12.6: Listing 12.6 Die Methode »gruss()« verwendet Felder — mittels »this« ist es immer das zum aufgerufenen Objekt gehörende Feld.

Book listing lst-0233-book.cpp:

struct Person {
    //… Rest wie zuvor …
    string gruss();
};
string Person::gruss() {
    return format("Hallo {} aus {}", this->name_, this->ort_);
}
int main() {
    Person anna { "Anna", 33, "Hof" };
    Person nina { "Nina", 22, "Wyk" };
    anna.gruss();
    nina.gruss();
}

Listing 12.7: Listing 12.7 So trennen Sie Methoden und Daten voneinander.

Book listing lst-0235-book.cpp:

string gruss(Person * const p) {  // impliziter Parameter explizit gemacht
    return format("Hallo {} aus {}", p->name_, p->ort_);
}

GodboltId:hEvqWqqc6

Book listing lst-0236-book.cpp:

// https://godbolt.org/z/hEvqWqqc6 
int wert = 5;                         // globale Variable
struct Wrap {
    int wert = 3;                     // Datenfeld
    void setze(int wert) {            // Parameter
        this->wert = wert + ::wert;
    }
};

Godbolt Listing lst-0236-godb.cpp, https://godbolt.org/z/hEvqWqqc6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hEvqWqqc6 
int wert = 5;                         // globale Variable
struct Wrap {
    int wert = 3;                     // Datenfeld
    void setze(int wert) {            // Parameter
        this->wert = wert + ::wert;
    }
};

Listing 12.8: Listing 12.8 »drucke« nimmt einen Stream als Argument.

Book listing lst-0239-book.cpp:

// https://godbolt.org/z/bjWKjaeaK 
// Ausschnitt. Person wie zuvor
void Person::drucke(std::ostream& os) {
    os << format("{} ({}) aus {}", name_, alter_,  ort_);
}
int main() {
    Person karl {"Karl", 12, "Stetten"};
    karl.drucke(cout);        // auf dem Bildschirm
    cout << "\n";
    std::ofstream datei {"personen.txt"};
    karl.drucke(datei);       // in eine Datei
    // automatischer Test:
    std::ostringstream oss{}; // schreibt in einen string
    karl.drucke(oss);
    if(oss.str() == "Karl (12) aus Stetten") {
        cout << "ok\n";
    } else {
        cout << "Fehler in Person::drucke!\n";
        return 1;             // Fehler nach außen weiterleiten
    }
}

Godbolt Listing lst-0239-godb.cpp, https://godbolt.org/z/bjWKjaeaK:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bjWKjaeaK 
// Ausschnitt. Person wie zuvor
void Person::drucke(std::ostream& os) {
    os << format("{} ({}) aus {}", name_, alter_,  ort_);
}
int main() {
    Person karl {"Karl", 12, "Stetten"};
    karl.drucke(cout);        // auf dem Bildschirm
    cout << "\n";
    std::ofstream datei {"personen.txt"};
    karl.drucke(datei);       // in eine Datei
    // automatischer Test:
    std::ostringstream oss{}; // schreibt in einen string
    karl.drucke(oss);
    if(oss.str() == "Karl (12) aus Stetten") {
        cout << "ok\n";
    } else {
        cout << "Fehler in Person::drucke!\n";
        return 1;             // Fehler nach außen weiterleiten
    }
}

Listing 12.9: Listing 12.9 Sie können den Standardoperator für die Ausgabe überladen.

Book listing lst-0240-book.cpp:

std::ostream& Person::drucke(std::ostream& os) {
    return os << format("{} ({}) aus {}", name_, alter_,  ort_);
}
std::ostream& operator<<(std::ostream& os, Person p) {
    return p.drucke(os);
}

Listing 12.10: Listing 12.10 Die Ausgabe mit << erreichen Sie durch Überladung einer freien Funktion.

Book listing lst-0242-book.cpp:

// https://godbolt.org/z/bEdfWqqnn 
// Ausschnitt …
    std::ostream& drucke(std::ostream& os);
};
std::ostream& Person::drucke(std::ostream& os) {
    return os << format("{} ({}) aus {}", p.name_, p.alter_,  p.ort_);
}
std::ostream& operator<<(std::ostream& os, Person p) {
    return p.drucke(os);
}
int main() {
    Person paul {"Paul", 23, "Dresden"};
    cout << "Sie sind " << paul << ", richtig?\n";
}

Godbolt Listing lst-0242-godb.cpp, https://godbolt.org/z/bEdfWqqnn:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bEdfWqqnn 
// Ausschnitt …
    std::ostream& drucke(std::ostream& os);
};
std::ostream& Person::drucke(std::ostream& os) {
    return os << format("{} ({}) aus {}", p.name_, p.alter_,  p.ort_);
}
std::ostream& operator<<(std::ostream& os, Person p) {
    return p.drucke(os);
}
int main() {
    Person paul {"Paul", 23, "Dresden"};
    cout << "Sie sind " << paul << ", richtig?\n";
}

Listing 12.11: Listing 12.11 Methoden können auch inline definiert werden.

Book listing lst-0243-book.cpp:

// https://godbolt.org/z/zf9Tc4ahs 
#include <string>
#include <iostream>    // ostream

using std::string; using std::ostream;

struct Person {
  string name_;
  int alter_;
  string ort_;
  ostream& drucke(ostream& os) {  // Methode inline definiert
    return os << format("{} ({}) aus {}", p.name_, p.alter_,  p.ort_);
  }
};

Godbolt Listing lst-0243-godb.cpp, https://godbolt.org/z/zf9Tc4ahs:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zf9Tc4ahs 
#include <string>
#include <iostream>    // ostream

using std::string; using std::ostream;

struct Person {
  string name_;
  int alter_;
  string ort_;
  ostream& drucke(ostream& os) {  // Methode inline definiert
    return os << format("{} ({}) aus {}", p.name_, p.alter_,  p.ort_);
  }
};

Listing 12.12: Listing 12.12 So definieren Sie einen Konstruktor.

Book listing lst-0248-book.cpp:

struct Person {
    string name_;
    int alter_;
    string ort_;
    Person();          // Konstruktor deklarieren
};
Person::Person()
  : name_{"kein Name"} // Initialisierungswert für name_
  , alter_{-1}         // Initialisierungswert für alter_
  , ort_{"kein Ort"}   // Initialisierungswert für ort_
{ }                    // leerer Funktionskörper

Listing 12.13: Listing 12.13 Auch mehrere Konstruktoren sind möglich.

Book listing lst-0250-book.cpp:

// https://godbolt.org/z/cqoTsWbhW 
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;

struct Person {
    string name_;
    int alter_;
    string ort_;
    Person();                         // Konstruktor ohne Argumente
    Person(sview n, int a, sview o);  // Konstruktor mit drei Argumenten
    Person(sview n, int a);           // Konstruktor mit zwei Argumenten
    Person(sview n);                  // Konstruktor mit einem Argument
};

Person::Person() 
  : name_{"kein Name"}, alter_{-1}, ort_{"kein Ort"} { } 
Person::Person(sview n, int a, sview o) 
  : name_{n}, alter_{a}, ort_{o} { } 
Person::Person(sview n, int a)
  : name_{n}, alter_{a}, ort_{"kein Ort"} { }
Person::Person(sview n)
  : name_{n}, alter_{-1}, ort_{"kein Ort"} { }

Godbolt Listing lst-0250-godb.cpp, https://godbolt.org/z/cqoTsWbhW:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cqoTsWbhW 
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;

struct Person {
    string name_;
    int alter_;
    string ort_;
    Person();                         // Konstruktor ohne Argumente
    Person(sview n, int a, sview o);  // Konstruktor mit drei Argumenten
    Person(sview n, int a);           // Konstruktor mit zwei Argumenten
    Person(sview n);                  // Konstruktor mit einem Argument
};

Person::Person() 
  : name_{"kein Name"}, alter_{-1}, ort_{"kein Ort"} { } 
Person::Person(sview n, int a, sview o) 
  : name_{n}, alter_{a}, ort_{o} { } 
Person::Person(sview n, int a)
  : name_{n}, alter_{a}, ort_{"kein Ort"} { }
Person::Person(sview n)
  : name_{n}, alter_{-1}, ort_{"kein Ort"} { }

Listing 12.14: Listing 12.14 Membervariablen können mit Defaultwerten ausgestattet werden.

Book listing lst-0251-book.cpp:

// https://godbolt.org/z/vzneMWW9r 
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;
struct Person {
    string name_ = "kein Name";
    int alter_ = -1;
    string ort_ = "kein Ort";
    Person() {}
    Person(sview n, int a, sview o)
      : name_{n}, alter_{a}, ort_{o} { }
    Person(sview n, int a)
      : name_{n}, alter_{a} { }
    Person(sview n)
      : name_{n} { }
};

Godbolt Listing lst-0251-godb.cpp, https://godbolt.org/z/vzneMWW9r:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vzneMWW9r 
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;
struct Person {
    string name_ = "kein Name";
    int alter_ = -1;
    string ort_ = "kein Ort";
    Person() {}
    Person(sview n, int a, sview o)
      : name_{n}, alter_{a}, ort_{o} { }
    Person(sview n, int a)
      : name_{n}, alter_{a} { }
    Person(sview n)
      : name_{n} { }
};

Listing 12.15: Listing 12.15 Ein Konstruktor kann einen Teil der Initialisierung an einen anderen Konstruktor weiterreichen.

Book listing lst-0252-book.cpp:

// https://godbolt.org/z/83efx7Gex 
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;

struct Person {
    string name_;
    int alter_;
    string ort_;

    Person(sview n, int a, sview o)                   // delegierter Konstruktor
      : name_(n), alter_(a), ort_(o) { }              // … ausimplementiert
    Person() : Person{"kein Name",-1,"kein Ort"} { }  // delegierend
    Person(sview n, int a) : Person{n, a, "kein Ort"} { } // delegierend
    Person(sview n) : Person{n, -1, "kein Ort"} { }       // delegierend
};

Godbolt Listing lst-0252-godb.cpp, https://godbolt.org/z/83efx7Gex:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/83efx7Gex 
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;

struct Person {
    string name_;
    int alter_;
    string ort_;

    Person(sview n, int a, sview o)                   // delegierter Konstruktor
      : name_(n), alter_(a), ort_(o) { }              // … ausimplementiert
    Person() : Person{"kein Name",-1,"kein Ort"} { }  // delegierend
    Person(sview n, int a) : Person{n, a, "kein Ort"} { } // delegierend
    Person(sview n) : Person{n, -1, "kein Ort"} { }       // delegierend
};

Listing 12.16: Listing 12.16 Auch ein Konstruktor kann mit Defaultparametern überladen werden.

Book listing lst-0253-book.cpp:

// https://godbolt.org/z/Exh4PnMTE 
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;

struct Person {
    string name_;
    int alter_;
    string ort_;

    Person(sview n = "N.N.", int a = 18, sview o = "Berlin")
      : name_(n), alter_(a), ort_(o) { }
};

Godbolt Listing lst-0253-godb.cpp, https://godbolt.org/z/Exh4PnMTE:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Exh4PnMTE 
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;

struct Person {
    string name_;
    int alter_;
    string ort_;

    Person(sview n = "N.N.", int a = 18, sview o = "Berlin")
      : name_(n), alter_(a), ort_(o) { }
};

Listing 12.17: Listing 12.17 Ein Konstruktor mit allen vorbesetzten Argumenten wird zum Defaultkonstruktor.

Book listing lst-0255-book.cpp:

// https://godbolt.org/z/vb1Wsr5d3 
#include <vector>
#include <string>
#include <string_view>
#include <iostream>
using std::string; using std::cout; using sview = std::string_view;

struct Person {
    string name_;
    int alter_;
    string ort_;
    // fungiert als Defaultkonstruktor:
    Person(sview n = "N.N.", int a = 18, sview o = "Berlin")
      : name_(n), alter_(a), ort_(o) { }
};

int main() {
    std::vector<Person> personen{}; // zunächst leer
    personen.resize(5); // auf fünf »leere« Personen erweitern
    cout << personen[3].ort_ << "\n"; // Ausgabe: Berlin
}

Godbolt Listing lst-0255-godb.cpp, https://godbolt.org/z/vb1Wsr5d3:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vb1Wsr5d3 
#include <vector>
#include <string>
#include <string_view>
#include <iostream>
using std::string; using std::cout; using sview = std::string_view;

struct Person {
    string name_;
    int alter_;
    string ort_;
    // fungiert als Defaultkonstruktor:
    Person(sview n = "N.N.", int a = 18, sview o = "Berlin")
      : name_(n), alter_(a), ort_(o) { }
};

int main() {
    std::vector<Person> personen{}; // zunächst leer
    personen.resize(5); // auf fünf »leere« Personen erweitern
    cout << personen[3].ort_ << "\n"; // Ausgabe: Berlin
}

Listing 12.18: Listing 12.18 Rufen Sie keine initialisierende Methode im Konstruktorkörper auf.

Book listing lst-0256-book.cpp:

// https://godbolt.org/z/osM9ncPzr 
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;

struct Person {
    string name_;
    int alter_;
    string ort_;
    Person(sview n, int a, sview o)
    {                   //                 (ERR)  Initialisierungsliste fehlt
        init(n, a, o);  //                 (ERR)  fragwürdiger »Initialisierungsaufruf«
    }
    void init(sview n, int a, sview o) {
      name_ = n; alter_ = a; ort_ = o;
    }
};

Godbolt Listing lst-0256-godb.cpp, https://godbolt.org/z/osM9ncPzr:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/osM9ncPzr 
#include <string>
#include <string_view>
using std::string; using sview = std::string_view;

struct Person {
    string name_;
    int alter_;
    string ort_;
    Person(sview n, int a, sview o)
    {                   //                 (ERR)  Initialisierungsliste fehlt
        init(n, a, o);  //                 (ERR)  fragwürdiger »Initialisierungsaufruf«
    }
    void init(sview n, int a, sview o) {
      name_ = n; alter_ = a; ort_ = o;
    }
};

Listing 12.19: Listing 12.19 Zugriff von außen auf die Datenfelder eines Typs

Book listing lst-0258-book.cpp:

ostream& operator<<(ostream& os, Person p) {
    return os << format("{} ({}) aus {}", p.name_, p.alter_, p.ort_);
}

Listing 12.20: Listing 12.20 Teilen Sie einen Typ mit »public« und »private« in mehrere Bereiche auf.

Book listing lst-0259-book.cpp:

// https://godbolt.org/z/zrE55vWq3 
#include <string>
#include <string_view>
using std::string; using std::string_view;

struct Person {
private: // alles ab hier kann von außen nicht benutzt werden
    string name_;
    int alter_;
    string ort_;
public:  // alles ab hier darf von außen verwendet werden
    Person(string_view n, int a, string_view o)
      : name_{n}, alter_{a}, ort_{o} { }
    void drucke();
};

Godbolt Listing lst-0259-godb.cpp, https://godbolt.org/z/zrE55vWq3:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zrE55vWq3 
#include <string>
#include <string_view>
using std::string; using std::string_view;

struct Person {
private: // alles ab hier kann von außen nicht benutzt werden
    string name_;
    int alter_;
    string ort_;
public:  // alles ab hier darf von außen verwendet werden
    Person(string_view n, int a, string_view o)
      : name_{n}, alter_{a}, ort_{o} { }
    void drucke();
};

Listing 12.21: Listing 12.21 »class« beginnt mit privater Sichtbarkeit.

Book listing lst-0260-book.cpp:

// https://godbolt.org/z/e6rqbq3bE 
#include <string>
#include <string_view>
using std::string; using std::string_view;

class Person { // eine Klasse beginnt mit privater Sichtbarkeit
    string name_;
    int alter_;
    string ort_;
public:  // alles ab hier darf von außen verwendet werden
    Person(string_view n, int a, string_view o)
      : name_{n}, alter_{a}, ort_{o} { }
    void drucke();
};

Godbolt Listing lst-0260-godb.cpp, https://godbolt.org/z/e6rqbq3bE:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/e6rqbq3bE 
#include <string>
#include <string_view>
using std::string; using std::string_view;

class Person { // eine Klasse beginnt mit privater Sichtbarkeit
    string name_;
    int alter_;
    string ort_;
public:  // alles ab hier darf von außen verwendet werden
    Person(string_view n, int a, string_view o)
      : name_{n}, alter_{a}, ort_{o} { }
    void drucke();
};

Listing 12.22: Listing 12.22 Teile der Daten sind privat.

Book listing lst-0261-book.cpp:

// https://godbolt.org/z/Pr76Y55P4 
class Rect {
    int area_;  // private Daten
public:
    int x_, y_;
    void set(int x, int y) { x_=x; y_=y; area_=x_*y_; }
    int calc() { return area_; }
};

Godbolt Listing lst-0261-godb.cpp, https://godbolt.org/z/Pr76Y55P4:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Pr76Y55P4 
class Rect {
    int area_;  // private Daten
public:
    int x_, y_;
    void set(int x, int y) { x_=x; y_=y; area_=x_*y_; }
    int calc() { return area_; }
};

Listing 12.23: Listing 12.23 Mit »= default« lassen Sie den Compiler Code erzeugen.

Book listing lst-0262-book.cpp:

// https://godbolt.org/z/PaG9nTs7s 
class Rect {
    int area_;         // private Daten

public:
    int x_, y_;
    void set(int x, int y) { x_=x; y_=y; area_=x_*y_; }
    int calc() { return area_; }
    Rect() = default;  // den Compiler einen Konstruktor generieren lassen
};
class Pow {
    int result_;       // private Daten; hält 'base' hoch 'exp'
public:
    int base_, exp_;
    void set(int b, int e) { /* ... */ }
    int calc() { return result_; }
    Pow() : result_{1},base_{1},exp_{1} {} // sinnvoll initialisieren
};

Godbolt Listing lst-0262-godb.cpp, https://godbolt.org/z/PaG9nTs7s:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/PaG9nTs7s 
class Rect {
    int area_;         // private Daten

public:
    int x_, y_;
    void set(int x, int y) { x_=x; y_=y; area_=x_*y_; }
    int calc() { return area_; }
    Rect() = default;  // den Compiler einen Konstruktor generieren lassen
};
class Pow {
    int result_;       // private Daten; hält 'base' hoch 'exp'
public:
    int base_, exp_;
    void set(int b, int e) { /* ... */ }
    int calc() { return result_; }
    Pow() : result_{1},base_{1},exp_{1} {} // sinnvoll initialisieren
};

Listing 12.24: Listing 12.24 Eigene Datentypen können vor Fehlern schützen — dies ist der erste Schritt dazu.

Book listing lst-0263-book.cpp:

// https://godbolt.org/z/r5EsnnsEG 
#include <string>       // string, stoi
#include <iostream>     // cin, cout, ostream
#include <format>
using std::ostream; using std::format;
class Year {  /* Hilfstypen für sicheres Datum */
    int value_; // z. B. 2024
public:
    Year(int v) : value_{v} {}
    int value() { return value_; }
};
class Month {
    int value_; // 1..12
public:
    Month(int v) : value_{v} {}
    int value() { return value_; }
};
class Day {
    int value_; // 1..31
public:
    Day(int v) : value_{v} {}
    int value() { return value_; }
};
/* typsicher konstruierendes Datum */
class Date {
    Year year_;
    Month month_ = 1;
    Day day_ = 1;
public:
    Date(int y) : year_{y}           // 1-Argument-Konstruktor
        {}                           // setzt 1. Januar des angegebenen Jahres
    Date(Year y, Month m, Day d)     // 3-Argument-Konstruktor
        : year_{y}, month_{m}, day_{d}
        {}
    ostream& print(ostream& os);     // z. B. 2024-04-20
};
ostream& Date::print(ostream& os) {  // z. B. 2024-04-20
    return os << format("{}-{:02}-{:02}",
        year_.value(), month_.value(), day_.value());
}
ostream& operator<<(ostream& os, Date d) {
    return d.print(os);
}
// http://codegolf.stackexchange.com/a/11146/1405, user Fors, 2014-02-25
Date ostern(Year year) {
    const int y = year.value();
    int a = y/100*1483 - y/400*2225 + 2613;
    int b = (y%19*3510 + a/25*319)/330%29;
    b = 148 - b - (y*5/4 + a - b)%7;
    return Date{Year{y}, Month{b/31}, Day{b%31 + 1}}; // Datum erzeugen
}
int main(int argc, const char *argv[] ) {
    /* Eingabe */
    int zahl {};
    if(argc > 1) {
        zahl = std::stoi(argv[1]);
    } else {
        std::cout << "Jahr? "; std::cin >> zahl;
    }
    /* Berechnung */
    Date date = ostern(zahl);  // implizite Konvertierung nach Year
    /* Ausgabe */
    std::cout << "Ostern: " << date << "\n";
}

Godbolt Listing lst-0263-godb.cpp, https://godbolt.org/z/r5EsnnsEG:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/r5EsnnsEG 
#include <string>       // string, stoi
#include <iostream>     // cin, cout, ostream
#include <format>
using std::ostream; using std::format;
class Year {  /* Hilfstypen für sicheres Datum */
    int value_; // z. B. 2024
public:
    Year(int v) : value_{v} {}
    int value() { return value_; }
};
class Month {
    int value_; // 1..12
public:
    Month(int v) : value_{v} {}
    int value() { return value_; }
};
class Day {
    int value_; // 1..31
public:
    Day(int v) : value_{v} {}
    int value() { return value_; }
};
/* typsicher konstruierendes Datum */
class Date {
    Year year_;
    Month month_ = 1;
    Day day_ = 1;
public:
    Date(int y) : year_{y}           // 1-Argument-Konstruktor
        {}                           // setzt 1. Januar des angegebenen Jahres
    Date(Year y, Month m, Day d)     // 3-Argument-Konstruktor
        : year_{y}, month_{m}, day_{d}
        {}
    ostream& print(ostream& os);     // z. B. 2024-04-20
};
ostream& Date::print(ostream& os) {  // z. B. 2024-04-20
    return os << format("{}-{:02}-{:02}",
        year_.value(), month_.value(), day_.value());
}
ostream& operator<<(ostream& os, Date d) {
    return d.print(os);
}
// http://codegolf.stackexchange.com/a/11146/1405, user Fors, 2014-02-25
Date ostern(Year year) {
    const int y = year.value();
    int a = y/100*1483 - y/400*2225 + 2613;
    int b = (y%19*3510 + a/25*319)/330%29;
    b = 148 - b - (y*5/4 + a - b)%7;
    return Date{Year{y}, Month{b/31}, Day{b%31 + 1}}; // Datum erzeugen
}
int main(int argc, const char *argv[] ) {
    /* Eingabe */
    int zahl {};
    if(argc > 1) {
        zahl = std::stoi(argv[1]);
    } else {
        std::cout << "Jahr? "; std::cin >> zahl;
    }
    /* Berechnung */
    Date date = ostern(zahl);  // implizite Konvertierung nach Year
    /* Ausgabe */
    std::cout << "Ostern: " << date << "\n";
}

Listing 12.25: Listing 12.25 Wenn alle »return«-Anweisungen dieselbe Variable zurückliefern, kann der Compiler eine Kopie immer vermeiden.

Book listing lst-0272-book.cpp:

// https://godbolt.org/z/T7afh4vxz 
#include <vector>
std::vector<int> createData(unsigned size) {
    std::vector<int> result{};
    for(int idx=0; idx<size; ++idx) {
        result.push_back(idx);
    }
    return result;
}

Godbolt Listing lst-0272-godb.cpp, https://godbolt.org/z/T7afh4vxz:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/T7afh4vxz 
#include <vector>
std::vector<int> createData(unsigned size) {
    std::vector<int> result{};
    for(int idx=0; idx<size; ++idx) {
        result.push_back(idx);
    }
    return result;
}

Listing 12.26: Listing 12.26 Mit »explicit« verhindern Sie automatische Typumwandlung.

Book listing lst-0281-book.cpp:

// jeweils nur Auszüge
class Year {
    explicit Year(int v) : value_{v} {}
};
class Month {
    explicit Month(int v) : value_{v} {}
};
class Day {
    explicit Day(int v) : value_{v} {}
};
class Date {
    explicit Date(int y) : year_{y} {}
};

Listing 12.27: Listing 12.27 »Year« hat nun kein »value()« mehr und benötigt dafür andere Methoden.

Book listing lst-0291-book.cpp:

// https://godbolt.org/z/EPz4Kd6jP 
class Year {
    int value_;
public:
    explicit Year(int v) : value_{v} {}
    std::ostream& print(std::ostream& os) const;
    Year& advance(const Year& other);
    bool equals(const Year& other) const;
    bool less_than(const Year& other) const;
};
std::ostream& Year::print(std::ostream& os) const {
    return os << value_;
}
std::ostream& operator<<(std::ostream& os, const Year& year) {
    return year.print(os);
}
Year& Year::advance(const Year& other) {
    value_ += other.value_;
    return *this;
}
bool Year::equals(const Year& other) const {
    return value_ == other.value_;
}
bool Year::less_than(const Year& other) const {
    return value_ < other.value_;
}

Godbolt Listing lst-0291-godb.cpp, https://godbolt.org/z/EPz4Kd6jP:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/EPz4Kd6jP 
class Year {
    int value_;
public:
    explicit Year(int v) : value_{v} {}
    std::ostream& print(std::ostream& os) const;
    Year& advance(const Year& other);
    bool equals(const Year& other) const;
    bool less_than(const Year& other) const;
};
std::ostream& Year::print(std::ostream& os) const {
    return os << value_;
}
std::ostream& operator<<(std::ostream& os, const Year& year) {
    return year.print(os);
}
Year& Year::advance(const Year& other) {
    value_ += other.value_;
    return *this;
}
bool Year::equals(const Year& other) const {
    return value_ == other.value_;
}
bool Year::less_than(const Year& other) const {
    return value_ < other.value_;
}

Listing 12.28: Listing 12.28 Gibt »advance« das Objekt selbst zurück, können Sie danach eine weitere Methode aufrufen.

Book listing lst-0292-book.cpp:

Year year{2024};
year.advance(Year{1}).advance(Year{3});
cout << year; // Ausgabe: 2028

Listing 12.29: Listing 12.29 Eine fließende Programmierschnittstelle erlaubt zuweilen übersichtlichen Code.

Book listing lst-0293-book.cpp:

Page page = Html().body()
    .h1("Ueberschrift")
    .table().border(0)
      .tr()
        .td().css("head").text("Hunderasse").end()
        .td().text("Pudel").end()
      .end()
    .end()
    .toPage();

Listing 12.30: Listing 12.30 Der eigentlich interne Typ »int« ist Teil der Schnittstelle der Klasse geworden.

Book listing lst-0294-book.cpp:

// https://godbolt.org/z/sP3W8jx6E 
class Year {
    int value_;                         // eigentlich intern verwendeter Typ
public:
    explicit Year(int v) : value_{v} {} // Typ wird Teil des Interface
    int value() { return value_; }      // auch bei der Rückgabe
};
int main() {
   Year year{ 2024 };                   // Typ int
   int val = year.value();              // passender Typ
}

Godbolt Listing lst-0294-godb.cpp, https://godbolt.org/z/sP3W8jx6E:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sP3W8jx6E 
class Year {
    int value_;                         // eigentlich intern verwendeter Typ
public:
    explicit Year(int v) : value_{v} {} // Typ wird Teil des Interface
    int value() { return value_; }      // auch bei der Rückgabe
};
int main() {
   Year year{ 2024 };                   // Typ int
   int val = year.value();              // passender Typ
}

Listing 12.31: Listing 12.31 Mit »using« können Sie Typaliase einführen, mit denen sich Interfaces leichter pflegen lassen als mit den Typen selbst.

Book listing lst-0295-book.cpp:

// https://godbolt.org/z/r3xaPv5Mr 
class Year {
public:
    using value_type = int;             // Typalias einführen
    value_type value_;                  // eigentlich intern verwendeter Typ
public:
    explicit Year(value_type v) : value_{v} {}
    value_type value() { return value_; }
};
int main() {
   Year year{ 2024 };                   // hier auf Compilerkonvertierung zählen
   Year::value_type val = year.value(); // verwenden Sie ::
}

Godbolt Listing lst-0295-godb.cpp, https://godbolt.org/z/r3xaPv5Mr:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/r3xaPv5Mr 
class Year {
public:
    using value_type = int;             // Typalias einführen
    value_type value_;                  // eigentlich intern verwendeter Typ
public:
    explicit Year(value_type v) : value_{v} {}
    value_type value() { return value_; }
};
int main() {
   Year year{ 2024 };                   // hier auf Compilerkonvertierung zählen
   Year::value_type val = year.value(); // verwenden Sie ::
}

Listing 12.32: Listing 12.32 Auch die Standardbibliothek enthält viele praktische Typaliase.

Book listing lst-0296-book.cpp:

// https://godbolt.org/z/vjTWjfKKz 
#include <vector>
#include <set>
#include <iostream>
using std::vector; using std::set; using std::cout;
using vector_t = vector<unsigned long long>; // Ihr eigener Typalias
int main() {
    vector_t huge{ 12ULL, 10'000'000'000ULL, 9ULL, 0ULL,  };
    vector_t::size_type sz = huge.size();
    vector_t::value_type uiuiui = huge[1];
    for(vector_t::iterator it = huge.begin(); it != huge.end(); ++it)
        *it *= 2; // verdoppeln
    /* sortieren per set */
    set<vector_t::value_type> sortiert{huge.begin(), huge.end()};
    for(vector_t::value_type val : sortiert)
        cout << val << " ";
    cout << "\n";
}

Godbolt Listing lst-0296-godb.cpp, https://godbolt.org/z/vjTWjfKKz:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vjTWjfKKz 
#include <vector>
#include <set>
#include <iostream>
using std::vector; using std::set; using std::cout;
using vector_t = vector<unsigned long long>; // Ihr eigener Typalias
int main() {
    vector_t huge{ 12ULL, 10'000'000'000ULL, 9ULL, 0ULL,  };
    vector_t::size_type sz = huge.size();
    vector_t::value_type uiuiui = huge[1];
    for(vector_t::iterator it = huge.begin(); it != huge.end(); ++it)
        *it *= 2; // verdoppeln
    /* sortieren per set */
    set<vector_t::value_type> sortiert{huge.begin(), huge.end()};
    for(vector_t::value_type val : sortiert)
        cout << val << " ";
    cout << "\n";
}

Listing 12.33: Listing 12.33 Bei der Initialisierung einer Variablen kann der Compiler den Typ ermitteln.

Book listing lst-0300-book.cpp:

// https://godbolt.org/z/Wh71cf7j1 
#include <vector>
#include <set>
#include <iostream> // cout
using std::vector; using std::set; using std::cout;
using vector_t = vector<unsigned long long>; // Ihr eigener Typalias
int main() {
    vector_t huge{ 12ULL, 10000000000ULL, 9ULL, 0ULL,  };
    auto sz = huge.size();
    auto uiuiui = huge[1];
    for(auto it = huge.begin(); it != huge.end(); ++it)
        *it *= 2; // verdoppeln
    /* sortieren per set */
    set sortiert(huge.begin(), huge.end());  // set<vector_t::value_type>
    for(auto val : sortiert)
        cout << val << " ";
    cout << "\n";
}

Godbolt Listing lst-0300-godb.cpp, https://godbolt.org/z/Wh71cf7j1:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Wh71cf7j1 
#include <vector>
#include <set>
#include <iostream> // cout
using std::vector; using std::set; using std::cout;
using vector_t = vector<unsigned long long>; // Ihr eigener Typalias
int main() {
    vector_t huge{ 12ULL, 10000000000ULL, 9ULL, 0ULL,  };
    auto sz = huge.size();
    auto uiuiui = huge[1];
    for(auto it = huge.begin(); it != huge.end(); ++it)
        *it *= 2; // verdoppeln
    /* sortieren per set */
    set sortiert(huge.begin(), huge.end());  // set<vector_t::value_type>
    for(auto val : sortiert)
        cout << val << " ";
    cout << "\n";
}

Listing 12.34: Listing 12.34 Typ-Deduktion mit »auto« können Sie mit einem Concept weiter einschränken.

Book listing lst-0301-book.cpp:

// https://godbolt.org/z/hT8o3dqrK 
#include <vector>
#include <set>
#include <iostream> // cout
#include <concepts> // integral
#include <iterator> // output_iterator, input_iterator
using namespace std;
using vector_t = vector<unsigned long long>;        // Ihr eigener Typalias
int main() {
  vector_t huge{ 12ULL, 10000000000ULL, 9ULL, 0ULL,  };
  unsigned_integral auto sz = huge.size();
  unsigned_integral auto uiuiui = huge[1];
  signed_integral auto meh = huge[1];               //             (ERR)  Concept nicht erfüllt
  input_or_output_iterator auto itx = huge.begin(); // Concept ohne Parameter
  for(output_iterator<unsigned long long> auto i=huge.begin();
      it!=huge.end(); ++it)
    *it *= 2; // verdoppeln
  /* sortieren per set */
  set sortiert(huge.begin(), huge.end());           // set<vector_t::value_type>
  for(const unsigned_integral auto& val : sortiert)
    cout << val << " ";
  cout << "\n";
}

Godbolt Listing lst-0301-godb.cpp, https://godbolt.org/z/hT8o3dqrK:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hT8o3dqrK 
#include <vector>
#include <set>
#include <iostream> // cout
#include <concepts> // integral
#include <iterator> // output_iterator, input_iterator
using namespace std;
using vector_t = vector<unsigned long long>;        // Ihr eigener Typalias
int main() {
  vector_t huge{ 12ULL, 10000000000ULL, 9ULL, 0ULL,  };
  unsigned_integral auto sz = huge.size();
  unsigned_integral auto uiuiui = huge[1];
  signed_integral auto meh = huge[1];               //             (ERR)  Concept nicht erfüllt
  input_or_output_iterator auto itx = huge.begin(); // Concept ohne Parameter
  for(output_iterator<unsigned long long> auto i=huge.begin();
      it!=huge.end(); ++it)
    *it *= 2; // verdoppeln
  /* sortieren per set */
  set sortiert(huge.begin(), huge.end());           // set<vector_t::value_type>
  for(const unsigned_integral auto& val : sortiert)
    cout << val << " ";
  cout << "\n";
}

Listing 12.35: Listing 12.35 Wenn Sie »auto« mit »&« anreichern, erhalten Sie eine veränderbare Referenz.

Book listing lst-0302-book.cpp:

// https://godbolt.org/z/ro6fdsvT9 
#include <vector>
#include <iostream> // cout
using std::vector; using std::cout;
int main() {
    vector data{ 12, 100, -1, 0,  };    // vector<int>
    for(auto& val : data)
        val *= 2; // verdoppeln
    for(const auto val : data)
        cout << val << " ";
    cout << "\n";
}

Godbolt Listing lst-0302-godb.cpp, https://godbolt.org/z/ro6fdsvT9:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ro6fdsvT9 
#include <vector>
#include <iostream> // cout
using std::vector; using std::cout;
int main() {
    vector data{ 12, 100, -1, 0,  };    // vector<int>
    for(auto& val : data)
        val *= 2; // verdoppeln
    for(const auto val : data)
        cout << val << " ";
    cout << "\n";
}

Listing 12.36: Listing 12.36 Um einen eigenen Datentyp in einen »vector« zu packen, muss dieser nicht viele Bedingungen erfüllen.

Book listing lst-0306-book.cpp:

// https://godbolt.org/z/8ejPs6zr6 
#include <vector>
struct Zahl {
    int wert_ = 0;
    Zahl() {} // Standardkonstruktor
    explicit Zahl(int w) : wert_{w} {}
};
int main() {
    std::vector<Zahl> zahlen{}; // okay: Zahl erfüllt die Bedingungen
    zahlen.push_back( Zahl{2} );
}

Godbolt Listing lst-0306-godb.cpp, https://godbolt.org/z/8ejPs6zr6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8ejPs6zr6 
#include <vector>
struct Zahl {
    int wert_ = 0;
    Zahl() {} // Standardkonstruktor
    explicit Zahl(int w) : wert_{w} {}
};
int main() {
    std::vector<Zahl> zahlen{}; // okay: Zahl erfüllt die Bedingungen
    zahlen.push_back( Zahl{2} );
}

Listing 12.37: Listing 12.37 Für einen »set« eines eigenen Datentyps müssen Sie »operator<« überschreiben.

Book listing lst-0307-book.cpp:

// https://godbolt.org/z/vrdKPvh7f 
#include <set>
struct Zahl {
    int wert_ = 0;
    explicit Zahl(int w) : wert_{w} {}
};
bool operator<(const Zahl& links, const Zahl& rechts) {
    return links.wert_ < rechts.wert_;
}
int main() {
    std::set<Zahl> zahlen{};  // okay
    zahlen.insert( Zahl{3} ); // hier wird operator< gebraucht
}

Godbolt Listing lst-0307-godb.cpp, https://godbolt.org/z/vrdKPvh7f:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vrdKPvh7f 
#include <set>
struct Zahl {
    int wert_ = 0;
    explicit Zahl(int w) : wert_{w} {}
};
bool operator<(const Zahl& links, const Zahl& rechts) {
    return links.wert_ < rechts.wert_;
}
int main() {
    std::set<Zahl> zahlen{};  // okay
    zahlen.insert( Zahl{3} ); // hier wird operator< gebraucht
}

GodboltId:M81MjePh5

Book listing lst-0308-book.cpp:

// https://godbolt.org/z/M81MjePh5 
#include <map>

struct Zahl {
    int wert_ = 0;
    explicit Zahl(int w) : wert_{w} {}
};

bool operator<(const Zahl& links, const Zahl& rechts) {
    return links.wert_ < rechts.wert_;
}

int main() {
    std::map<Zahl,int> zahlen{};                  // okay
    zahlen.insert( std::make_pair(Zahl{4},100) ); // braucht operator<
    zahlen[Zahl{5}] = 200;                        // hier ebenfalls
}

Godbolt Listing lst-0308-godb.cpp, https://godbolt.org/z/M81MjePh5:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M81MjePh5 
#include <map>

struct Zahl {
    int wert_ = 0;
    explicit Zahl(int w) : wert_{w} {}
};

bool operator<(const Zahl& links, const Zahl& rechts) {
    return links.wert_ < rechts.wert_;
}

int main() {
    std::map<Zahl,int> zahlen{};                  // okay
    zahlen.insert( std::make_pair(Zahl{4},100) ); // braucht operator<
    zahlen[Zahl{5}] = 200;                        // hier ebenfalls
}

Listing 13.1: Sie definieren einen Namensraum mit »namespace«.

Book listing lst-0311-book.cpp:

// https://godbolt.org/z/T1ohsxbje 
#include <string>
#include <iostream>                    // ostream, cout
namespace plant {
    class Baum {
        std::string name_;
    public:
        explicit Baum(const std::string_view name) : name_{name} {}
        void print(std::ostream& os) const { os << name_; }
    };
    std::ostream& operator<<(std::ostream& os, const Baum& arg)
        { arg.print(os); return os; }
    using NadelBaum = Baum;            // für spätere Erweiterungen …
    using LaubBaum = Baum;             // … vorsorgen
    namespace beispielnamen {          // eingebetteter Namensraum
        std::string eicheName = "Eiche";
        std::string bucheName = "Buche";
        std::string tanneName = "Tanne";
    } // Ende namespace beispielnamen
} // Ende namespace plant

int main() {  // main darf nicht in einem Namespace stehen
    using namespace plant::beispielnamen; // alle Beispielnamen verfügbar machen
    plant::NadelBaum tanne{ tanneName };
    plant::LaubBaum eiche{ eicheName };
    tanne.print(std::cout); std::cout << "\n";
    using plant::operator<<;           // ohne geht 'cout << eiche' nicht
    std::cout << eiche << "\n";
}

Godbolt Listing lst-0311-godb.cpp, https://godbolt.org/z/T1ohsxbje:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/T1ohsxbje 
#include <string>
#include <iostream>                    // ostream, cout
namespace plant {
    class Baum {
        std::string name_;
    public:
        explicit Baum(const std::string_view name) : name_{name} {}
        void print(std::ostream& os) const { os << name_; }
    };
    std::ostream& operator<<(std::ostream& os, const Baum& arg)
        { arg.print(os); return os; }
    using NadelBaum = Baum;            // für spätere Erweiterungen …
    using LaubBaum = Baum;             // … vorsorgen
    namespace beispielnamen {          // eingebetteter Namensraum
        std::string eicheName = "Eiche";
        std::string bucheName = "Buche";
        std::string tanneName = "Tanne";
    } // Ende namespace beispielnamen
} // Ende namespace plant

int main() {  // main darf nicht in einem Namespace stehen
    using namespace plant::beispielnamen; // alle Beispielnamen verfügbar machen
    plant::NadelBaum tanne{ tanneName };
    plant::LaubBaum eiche{ eicheName };
    tanne.print(std::cout); std::cout << "\n";
    using plant::operator<<;           // ohne geht 'cout << eiche' nicht
    std::cout << eiche << "\n";
}

Listing 13.2: In getrennten Namensräumen können Sie die gleichen Operatoren definieren.

Book listing lst-0315-book.cpp:

namespace plant {
    // … wie zuvor …
    std::ostream& operator<<(std::ostream&, const Baum&) {};
    namespace debug {
        std::ostream& operator<<(std::ostream&, const Baum&) {};
    }
}
plant::Baum baum{"MeinBaum"};
void run() {
    using namespace plant;
    cout << baum << "\n";
}
void diagnostic() {
    using namespace plant::debug;
    cout << baum << "\n";
}
int main() {
    run();
    diagnostic();
}

Listing 13.3: Ein anonymer Namensraum macht Definitionen lokal für die aktuelle Datei.

Book listing lst-0316-book.cpp:

// https://godbolt.org/z/M6EnPT3Gr 
// modul.hpp
#include <string>
#include <iostream>
namespace plant {
    class Baum {
        std::string name_;
    public:
        explicit Baum(const std::string_view name);
        void print(std::ostream& os) const;
    };
    std::ostream& operator<<(std::ostream& os, const Baum& arg);
}
// modul.cpp
#include "modul.hpp"
namespace {  // anonymer Namensraum
    std::string PREFIX = "BAUM:";
    void printInfo(std::ostream& os) {
        os << "Autor: Torsten T. Will\n";
    }
}
bool debug = false;  // global, kein Namensraum
namespace plant {
    Baum::Baum(const std::string_view name)
        : name_{name} {}
    void Baum::print(std::ostream& os) const {
        os << PREFIX << name_;
    }
    std::ostream& operator<<(std::ostream& os, const Baum& arg) {
        if(debug) printInfo(os);
        arg.print(os); return os;
    }
}
// main.cpp
#include "modul.hpp"
int main() {
    plant::Baum x{"x"};
    x.print(std::cout); std::cout << "\n";
}

Godbolt Listing lst-0316-godb.cpp, https://godbolt.org/z/M6EnPT3Gr:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M6EnPT3Gr 
// modul.hpp
#include <string>
#include <iostream>
namespace plant {
    class Baum {
        std::string name_;
    public:
        explicit Baum(const std::string_view name);
        void print(std::ostream& os) const;
    };
    std::ostream& operator<<(std::ostream& os, const Baum& arg);
}
// modul.cpp
#include "modul.hpp"
namespace {  // anonymer Namensraum
    std::string PREFIX = "BAUM:";
    void printInfo(std::ostream& os) {
        os << "Autor: Torsten T. Will\n";
    }
}
bool debug = false;  // global, kein Namensraum
namespace plant {
    Baum::Baum(const std::string_view name)
        : name_{name} {}
    void Baum::print(std::ostream& os) const {
        os << PREFIX << name_;
    }
    std::ostream& operator<<(std::ostream& os, const Baum& arg) {
        if(debug) printInfo(os);
        arg.print(os); return os;
    }
}
// main.cpp
#include "modul.hpp"
int main() {
    plant::Baum x{"x"};
    x.print(std::cout); std::cout << "\n";
}

GodboltId:cTYhMfo5W

Book listing lst-0317-book.cpp:

// https://godbolt.org/z/cTYhMfo5W 
// modul.cpp
#include "modul.hpp"
static std::string PREFIX = "BAUM:";
static void printInfo(std::ostream& os) {
    os << "Autor: Torsten T. Will\n";
}
bool debug = false;
// Rest wie bisher

Godbolt Listing lst-0317-godb.cpp, https://godbolt.org/z/cTYhMfo5W:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cTYhMfo5W 
// modul.cpp
#include "modul.hpp"
static std::string PREFIX = "BAUM:";
static void printInfo(std::ostream& os) {
    os << "Autor: Torsten T. Will\n";
}
bool debug = false;
// Rest wie bisher

Listing 13.4: Alle Instanzen teilen sich ihre »static«-Datenfelder und -Methoden.

Book listing lst-0319-book.cpp:

// https://godbolt.org/z/n4e8xdEGj 
#include <iostream> // cout
#include <string>
using std::string;
class Tree {
    static size_t countConstructed_;
    static size_t countDestructed_;
    string kind_;
    Tree(string kind) : kind_{kind}      // privater Konstruktor
        { ++countConstructed_; }
public:
    Tree(const Tree& o) : kind_{o.kind_}
        { ++countConstructed_; }
    string getKind() const { return kind_; }
    ~Tree() { ++countDestructed_; }
    static Tree create(string kind) { return Tree{kind}; }
    static void stats(std::ostream& os) {
        os << "Constructed:+" << countConstructed_
           << " Destructed:-" << countDestructed_ << "\n";
    }
};
size_t Tree::countConstructed_ = 0;
size_t Tree::countDestructed_ = 0;
int main() {
    Tree birke = Tree::create("Birke");
    for(auto kind : {"Esche", "Eibe", "Eiche"}) {
        Tree temp = Tree::create(kind);
        std::cout << temp.getKind() << "\n";
    }
    Tree::stats(std::cout);
}

Godbolt Listing lst-0319-godb.cpp, https://godbolt.org/z/n4e8xdEGj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/n4e8xdEGj 
#include <iostream> // cout
#include <string>
using std::string;
class Tree {
    static size_t countConstructed_;
    static size_t countDestructed_;
    string kind_;
    Tree(string kind) : kind_{kind}      // privater Konstruktor
        { ++countConstructed_; }
public:
    Tree(const Tree& o) : kind_{o.kind_}
        { ++countConstructed_; }
    string getKind() const { return kind_; }
    ~Tree() { ++countDestructed_; }
    static Tree create(string kind) { return Tree{kind}; }
    static void stats(std::ostream& os) {
        os << "Constructed:+" << countConstructed_
           << " Destructed:-" << countDestructed_ << "\n";
    }
};
size_t Tree::countConstructed_ = 0;
size_t Tree::countDestructed_ = 0;
int main() {
    Tree birke = Tree::create("Birke");
    for(auto kind : {"Esche", "Eibe", "Eiche"}) {
        Tree temp = Tree::create(kind);
        std::cout << temp.getKind() << "\n";
    }
    Tree::stats(std::cout);
}

GodboltId:b9arcEMM1

Book listing lst-0321-book.cpp:

// https://godbolt.org/z/b9arcEMM1 
constinit auto SZ = 10*1000-1;                 // globale Variable
size_t autoincrement() {
    static constinit size_t i = 0;             // lokale statische Variable
    return i++;
}
class BraitenbergVehicle {
    inline static constinit size_t count_ = 0; // Klassenvariable
public:
    size_t id_;
    BraitenbergVehicle() : id_{++count_} {}
    ~BraitenbergVehicle() { --count_; }
};

Godbolt Listing lst-0321-godb.cpp, https://godbolt.org/z/b9arcEMM1:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/b9arcEMM1 
constinit auto SZ = 10*1000-1;                 // globale Variable
size_t autoincrement() {
    static constinit size_t i = 0;             // lokale statische Variable
    return i++;
}
class BraitenbergVehicle {
    inline static constinit size_t count_ = 0; // Klassenvariable
public:
    size_t id_;
    BraitenbergVehicle() : id_{++count_} {}
    ~BraitenbergVehicle() { --count_; }
};

Listing 13.5: Eine lokale statische Variable wird einmal initialisiert und danach wiederverwendet.

Book listing lst-0322-book.cpp:

// https://godbolt.org/z/h5qond6db 
#include <iostream>                     // cout
class Keyboard {
    Keyboard(const Keyboard&) = delete; // keine Kopie
    const size_t nr_;                   // aktuelle Nummer
public:
    static inline size_t count_ = 0;    // zählt erzeugte Instanzen
    explicit Keyboard() : nr_{count_++} {
        std::cout << "  Keyboard().nr:"<<nr_<<"\n";
    }
};
Keyboard& getKeyboard() {
    std::cout << "  getKeyboard()\n";
    static Keyboard keyboard{};         // statische lokale Variable
    return keyboard;
}
void func() {
    std::cout << "kbFunc...\n";
    Keyboard& kbFunc = getKeyboard();
}
int main() {
    std::cout << "kbA...\n";
    Keyboard& kbA = getKeyboard();
    func();
    std::cout << "kbB...\n";
    Keyboard& kbB = getKeyboard();
    std::cout << "count:" << Keyboard::count_ << "\n";
}

Godbolt Listing lst-0322-godb.cpp, https://godbolt.org/z/h5qond6db:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h5qond6db 
#include <iostream>                     // cout
class Keyboard {
    Keyboard(const Keyboard&) = delete; // keine Kopie
    const size_t nr_;                   // aktuelle Nummer
public:
    static inline size_t count_ = 0;    // zählt erzeugte Instanzen
    explicit Keyboard() : nr_{count_++} {
        std::cout << "  Keyboard().nr:"<<nr_<<"\n";
    }
};
Keyboard& getKeyboard() {
    std::cout << "  getKeyboard()\n";
    static Keyboard keyboard{};         // statische lokale Variable
    return keyboard;
}
void func() {
    std::cout << "kbFunc...\n";
    Keyboard& kbFunc = getKeyboard();
}
int main() {
    std::cout << "kbA...\n";
    Keyboard& kbA = getKeyboard();
    func();
    std::cout << "kbB...\n";
    Keyboard& kbB = getKeyboard();
    std::cout << "count:" << Keyboard::count_ << "\n";
}

Listing 13.6: Das Meyers-Singleton

Book listing lst-0323-book.cpp:

Keyboard& getKeyboard() {
    cout << "  getKeyboard()\n";
    static Keyboard keyboard{}; // statische lokale Variable
    return keyboard;
}

Listing 13.7: Die Bezeichner eines inline namespace gehen zusätzlich in seinen umgebenden Namensraum.

Book listing lst-0324-book.cpp:

// https://godbolt.org/z/115M1csEE 
#include <iostream>
namespace mylib {
    namespace v1 {
        int version() { return 1; }
    }
    inline namespace v2 { // aktuelle Version
        int version() { return 2; }
    }
}

int main() {
    std::cout << "Version " << mylib::version() << "\n";     // Ausgabe: 2
    std::cout << "Version " << mylib::v1::version() << "\n"; // Ausgabe: 1
    std::cout << "Version " << mylib::v2::version() << "\n"; // Ausgabe: 2
}

Godbolt Listing lst-0324-godb.cpp, https://godbolt.org/z/115M1csEE:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/115M1csEE 
#include <iostream>
namespace mylib {
    namespace v1 {
        int version() { return 1; }
    }
    inline namespace v2 { // aktuelle Version
        int version() { return 2; }
    }
}

int main() {
    std::cout << "Version " << mylib::version() << "\n";     // Ausgabe: 2
    std::cout << "Version " << mylib::v1::version() << "\n"; // Ausgabe: 1
    std::cout << "Version " << mylib::v2::version() << "\n"; // Ausgabe: 2
}

GodboltId:WTWxYa3rd

Book listing lst-0334-book.cpp:

// https://godbolt.org/z/WTWxYa3rd 
class Widget {
    unsigned x = 0, y = 0, w = 0, h = 0; // zum Beispiel
public:
    unsigned getLeft() const;
    unsigned getTop() const;
    unsigned getRight() const;
    unsigned getBottom() const;
    void setWidth(unsigned w);
    void setHeight(unsigned h);
};

Godbolt Listing lst-0334-godb.cpp, https://godbolt.org/z/WTWxYa3rd:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WTWxYa3rd 
class Widget {
    unsigned x = 0, y = 0, w = 0, h = 0; // zum Beispiel
public:
    unsigned getLeft() const;
    unsigned getTop() const;
    unsigned getRight() const;
    unsigned getBottom() const;
    void setWidth(unsigned w);
    void setHeight(unsigned h);
};

Listing 13.8: Lokale Konstanten einer Datei passen gut in einen anonymen Namensraum.

Book listing lst-0339-book.cpp:

// https://godbolt.org/z/q3Ga7hTGa 
#include <vector>
namespace {                         // anonymer Namensraum für Konstanten
    const unsigned DATA_SIZE = 100; /* Anzahl Elemente in Data */
    const double LIMIT = 999.999;   /* Maxwert bei Initialisierung */
};
std::vector<int> createData() {
    std::vector<int> result(DATA_SIZE);
    double currVal = 1.0;
    for(auto &elem : result) {
        elem = currVal;
        currVal *= 2;         // nächster Wert ist größer
        if(currVal > LIMIT) {
            currVal = LIMIT;  // kein Wert darf größer sein
        }
    }
    return result;
}

Godbolt Listing lst-0339-godb.cpp, https://godbolt.org/z/q3Ga7hTGa:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/q3Ga7hTGa 
#include <vector>
namespace {                         // anonymer Namensraum für Konstanten
    const unsigned DATA_SIZE = 100; /* Anzahl Elemente in Data */
    const double LIMIT = 999.999;   /* Maxwert bei Initialisierung */
};
std::vector<int> createData() {
    std::vector<int> result(DATA_SIZE);
    double currVal = 1.0;
    for(auto &elem : result) {
        elem = currVal;
        currVal *= 2;         // nächster Wert ist größer
        if(currVal > LIMIT) {
            currVal = LIMIT;  // kein Wert darf größer sein
        }
    }
    return result;
}

GodboltId:9Esx13h9r

Book listing lst-0340-book.cpp:

// https://godbolt.org/z/9Esx13h9r 
struct Widget {
    int num_ = 0;
    void setNumber(int x) {    // eine Nicht-const-Methode
        num_=x;
    }
};
Widget createWidget() {        // Rückgabe als Wert
    Widget result{};           // Erzeugen
    return result;
}
int main() {
    Widget w = createWidget(); // Rückgabe als Wert erzeugt Kopie
    w.setNumber(100);          // verändern, natürlich okay, w ist nicht-const
}

Godbolt Listing lst-0340-godb.cpp, https://godbolt.org/z/9Esx13h9r:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9Esx13h9r 
struct Widget {
    int num_ = 0;
    void setNumber(int x) {    // eine Nicht-const-Methode
        num_=x;
    }
};
Widget createWidget() {        // Rückgabe als Wert
    Widget result{};           // Erzeugen
    return result;
}
int main() {
    Widget w = createWidget(); // Rückgabe als Wert erzeugt Kopie
    w.setNumber(100);          // verändern, natürlich okay, w ist nicht-const
}

Listing 13.9: Obwohl der Rückgabetyp hier mit »const« markiert ist, wirkt es sich nicht aus, denn es wird immer kopiert.

Book listing lst-0341-book.cpp:

// https://godbolt.org/z/erv34b67c 
const Widget createWidget() {  // Rückgabe als const-Wert
    Widget result{};
    return result;
}
int main() {
    Widget w = createWidget(); // kopiert in neues nicht-const w
    w.setNumber(100);          // w ist nicht-const, verändern ist okay
}

Godbolt Listing lst-0341-godb.cpp, https://godbolt.org/z/erv34b67c:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/erv34b67c 
const Widget createWidget() {  // Rückgabe als const-Wert
    Widget result{};
    return result;
}
int main() {
    Widget w = createWidget(); // kopiert in neues nicht-const w
    w.setNumber(100);          // w ist nicht-const, verändern ist okay
}

Listing 13.10: Konstante Referenzen in Rückgaben

Book listing lst-0342-book.cpp:

// https://godbolt.org/z/v1TP6aYxT 
#include <string>
#include <string_view>
using std::string; using std::string_view;
class Widget {
    string name_ = "";
public:
    void setName(string_view newName) {
        name_ = newName;
    }
    const string& getName() const {    // const&-Rückgabe
        return name_;
    }
};
int main() {
    Widget w{};
    w.setName("Titel");
    string name1 = w.getName();        // neuer String, also Kopie
    name1.clear();                     // die Kopie dürfen Sie wieder verändern
    const string& name2 = w.getName(); // const-Referenz auf inneren string name_
    /* name2.clear(); */                   // name2 ist const, geht also nicht
    string& name3 = w.getName();       //                 (ERR)  Funktion gibt const& zurück, nicht &.
    auto name4 = w.getName();          // identisch mit name1
    const auto& name5 = w.getName();   // identisch mit name2
}

Godbolt Listing lst-0342-godb.cpp, https://godbolt.org/z/v1TP6aYxT:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/v1TP6aYxT 
#include <string>
#include <string_view>
using std::string; using std::string_view;
class Widget {
    string name_ = "";
public:
    void setName(string_view newName) {
        name_ = newName;
    }
    const string& getName() const {    // const&-Rückgabe
        return name_;
    }
};
int main() {
    Widget w{};
    w.setName("Titel");
    string name1 = w.getName();        // neuer String, also Kopie
    name1.clear();                     // die Kopie dürfen Sie wieder verändern
    const string& name2 = w.getName(); // const-Referenz auf inneren string name_
    /* name2.clear(); */                   // name2 ist const, geht also nicht
    string& name3 = w.getName();       //                 (ERR)  Funktion gibt const& zurück, nicht &.
    auto name4 = w.getName();          // identisch mit name1
    const auto& name5 = w.getName();   // identisch mit name2
}

Listing 13.11: Referenzen können konstant und nicht konstant zurückgegeben werden.

Book listing lst-0343-book.cpp:

// https://godbolt.org/z/rMrKbrdWe 
#include <string>
#include <iostream>
using std::string; using std::cout;

class Widget {
    string name_{};
public:
    const string& readName() const;        // const&-Rückgabe, const-Methode
    string& getName();                     // &-Rückgabe
};

const string& Widget::readName() const { return name_; }
string& Widget::getName() { return name_; }

int main() {
    Widget w{};
    const string& readonly = w.readName(); // const&, unveränderbar
    cout << "Name: " << readonly << "\n";  // noch "" leer.
    string& readwrite = w.getName();       // &, veränderbar
    readwrite.append("dran");       // verändert auch name_ und readonly
    cout << "Name per readwrite: " << readwrite << "\n"; // "dran"
    cout << "Name per readonly: " << readonly << "\n";   // auch "dran"
}

Godbolt Listing lst-0343-godb.cpp, https://godbolt.org/z/rMrKbrdWe:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rMrKbrdWe 
#include <string>
#include <iostream>
using std::string; using std::cout;

class Widget {
    string name_{};
public:
    const string& readName() const;        // const&-Rückgabe, const-Methode
    string& getName();                     // &-Rückgabe
};

const string& Widget::readName() const { return name_; }
string& Widget::getName() { return name_; }

int main() {
    Widget w{};
    const string& readonly = w.readName(); // const&, unveränderbar
    cout << "Name: " << readonly << "\n";  // noch "" leer.
    string& readwrite = w.getName();       // &, veränderbar
    readwrite.append("dran");       // verändert auch name_ und readonly
    cout << "Name per readwrite: " << readwrite << "\n"; // "dran"
    cout << "Name per readonly: " << readonly << "\n";   // auch "dran"
}

GodboltId:hsWrnaEea

Book listing lst-0346-book.cpp:

// https://godbolt.org/z/hsWrnaEea 
namespace {
    const int MAX_A = 12;       // das Gleiche wie MAX_B, aber kein static nötig
}
static const int MAX_B = 10;    // im globalen Namensraum
struct Data {
    static const int SIZE = 14; // als Datenfeld in einer Klasse
}

void func() {
    static const int LIMIT =16; // als lokale Konstante
}

Godbolt Listing lst-0346-godb.cpp, https://godbolt.org/z/hsWrnaEea:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hsWrnaEea 
namespace {
    const int MAX_A = 12;       // das Gleiche wie MAX_B, aber kein static nötig
}
static const int MAX_B = 10;    // im globalen Namensraum
struct Data {
    static const int SIZE = 14; // als Datenfeld in einer Klasse
}

void func() {
    static const int LIMIT =16; // als lokale Konstante
}

Listing 13.12: Manche Ausdrücke müssen zur Übersetzungszeit bekannt sein.

Book listing lst-0347-book.cpp:

// https://godbolt.org/z/5b3bvKd9r 
#include <array>
int main() {

    std::array<int, 5> arr5{};     // Literal und somit ein konstanter Ausdruck
    std::array<int, 2+3> arr23{};  // 2+3 kann der Compiler auswerten

    const size_t SIZE = 5;         // definiert eine Konstante
    std::array<int, SIZE> arrSC{}; // kann der Compiler verwenden — oft
    size_t size = 7;

    std::array<int,size> arrVar{}; // eine Variable können Sie nicht verwenden
}

Godbolt Listing lst-0347-godb.cpp, https://godbolt.org/z/5b3bvKd9r:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5b3bvKd9r 
#include <array>
int main() {

    std::array<int, 5> arr5{};     // Literal und somit ein konstanter Ausdruck
    std::array<int, 2+3> arr23{};  // 2+3 kann der Compiler auswerten

    const size_t SIZE = 5;         // definiert eine Konstante
    std::array<int, SIZE> arrSC{}; // kann der Compiler verwenden — oft
    size_t size = 7;

    std::array<int,size> arrVar{}; // eine Variable können Sie nicht verwenden
}

Listing 13.13: Ob der Compiler eine Konstante in einem konstanten Ausdruck verwenden kann, ist nicht immer sofort ersichtlich.

Book listing lst-0348-book.cpp:

// https://godbolt.org/z/MEGfeanPP 
#include <array>
struct Data {
    static const size_t SPAET;            // Konstante deklarieren
    static const size_t FRUEH;            // Konstante deklarieren
};

void func() {
    int x = Data::SPAET;                  // Konstante verwenden
}

const size_t Data::FRUEH = 10;            // Konstante definieren

std::array<int, Data::FRUEH> arrFRUEH {}; // Konstante verwenden
std::array<int, Data::SPAET> arrSPAET {}; //                 (ERR)  Konstante verwenden
const size_t Data::SPAET = 10;            // Konstante definieren

int main() {
    func();
}

Godbolt Listing lst-0348-godb.cpp, https://godbolt.org/z/MEGfeanPP:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MEGfeanPP 
#include <array>
struct Data {
    static const size_t SPAET;            // Konstante deklarieren
    static const size_t FRUEH;            // Konstante deklarieren
};

void func() {
    int x = Data::SPAET;                  // Konstante verwenden
}

const size_t Data::FRUEH = 10;            // Konstante definieren

std::array<int, Data::FRUEH> arrFRUEH {}; // Konstante verwenden
std::array<int, Data::SPAET> arrSPAET {}; //                 (ERR)  Konstante verwenden
const size_t Data::SPAET = 10;            // Konstante definieren

int main() {
    func();
}

Listing 13.14: Mit »constexpr« sieht der Compiler, wann ein Ausdruck nicht früh berechenbar ist.

Book listing lst-0350-book.cpp:

// https://godbolt.org/z/ba9rv6P51 
struct Data {
    static constexpr size_t SPAET; //                 (ERR)  klappt nicht ohne direkte Initialisierung
    static constexpr size_t FRUEH = 10;
};
constexpr size_t Data::SPAET = 10; //                 (ERR)  bei constexpr geht Definition nicht wie bei const

Godbolt Listing lst-0350-godb.cpp, https://godbolt.org/z/ba9rv6P51:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ba9rv6P51 
struct Data {
    static constexpr size_t SPAET; //                 (ERR)  klappt nicht ohne direkte Initialisierung
    static constexpr size_t FRUEH = 10;
};
constexpr size_t Data::SPAET = 10; //                 (ERR)  bei constexpr geht Definition nicht wie bei const

GodboltId:Krjh8M3aP

Book listing lst-0351-book.cpp:

// https://godbolt.org/z/Krjh8M3aP 
constexpr size_t verdoppleWennZuKlein1(size_t wert) {
   return wert < 100 ? wert*2 : wert; // liefert das Doppelte zurück, wenn kleiner 100
}
std::array<int, verdoppleWennZuKlein1(50)> arr {};

Godbolt Listing lst-0351-godb.cpp, https://godbolt.org/z/Krjh8M3aP:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Krjh8M3aP 
constexpr size_t verdoppleWennZuKlein1(size_t wert) {
   return wert < 100 ? wert*2 : wert; // liefert das Doppelte zurück, wenn kleiner 100
}
std::array<int, verdoppleWennZuKlein1(50)> arr {};

GodboltId:KPc6ExMaY

Book listing lst-0352-book.cpp:

// https://godbolt.org/z/KPc6ExMaY 
const size_t verdoppleWennZuKlein2(size_t wert) {
    return wert < 100 ? wert*2 : wert;
}
std::array<int, verdoppleWennZuKlein2(50)> arr {}; //                     (ERR)  nicht konstant genug

Godbolt Listing lst-0352-godb.cpp, https://godbolt.org/z/KPc6ExMaY:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KPc6ExMaY 
const size_t verdoppleWennZuKlein2(size_t wert) {
    return wert < 100 ? wert*2 : wert;
}
std::array<int, verdoppleWennZuKlein2(50)> arr {}; //                     (ERR)  nicht konstant genug

Listing 13.15: Mit »if constexpr« können Sie zur Übersetzungszeit entscheiden, welcher Code ausgeführt wird.

Book listing lst-0354-book.cpp:

// https://godbolt.org/z/zMbnYzo17 
template<typename T>
auto deref(T t) {
    if constexpr (std::is_pointer_v<T>) {
        return *t;
    } else {
        return t;
    }
}
int main() {
    int i = 42;
    std::cout << deref(i) << '\n';         // direkt der Wert
    auto p = std::make_unique<int>(73);
    std::cout << deref(p.get()) << '\n';   // dereferenzierter Pointer
}

Godbolt Listing lst-0354-godb.cpp, https://godbolt.org/z/zMbnYzo17:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zMbnYzo17 
template<typename T>
auto deref(T t) {
    if constexpr (std::is_pointer_v<T>) {
        return *t;
    } else {
        return t;
    }
}
int main() {
    int i = 42;
    std::cout << deref(i) << '\n';         // direkt der Wert
    auto p = std::make_unique<int>(73);
    std::cout << deref(p.get()) << '\n';   // dereferenzierter Pointer
}

Listing 13.16: »if constexpr« funktioniert auch mit »else«

Book listing lst-0355-book.cpp:

// https://godbolt.org/z/eo468MvMo 
#include <iostream>
#include <string>
struct S {
   int n;
   std::string s;
   float d;
};
template <std::size_t N> auto& get(S& s) {
    if constexpr (N == 0) return s.n;
    else if constexpr (N == 1) return s.s;
    else if constexpr (N == 2) return s.d;
}
int main() {
    S obj { 0, "hello", 10.0f };
    std::cout << get<0>(obj) << ", " << get<1>(obj) << "\n"; // Ausgabe: 0, hello
}

Godbolt Listing lst-0355-godb.cpp, https://godbolt.org/z/eo468MvMo:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eo468MvMo 
#include <iostream>
#include <string>
struct S {
   int n;
   std::string s;
   float d;
};
template <std::size_t N> auto& get(S& s) {
    if constexpr (N == 0) return s.n;
    else if constexpr (N == 1) return s.s;
    else if constexpr (N == 2) return s.d;
}
int main() {
    S obj { 0, "hello", 10.0f };
    std::cout << get<0>(obj) << ", " << get<1>(obj) << "\n"; // Ausgabe: 0, hello
}

GodboltId:44KMf1fWr

Book listing lst-0356-book.cpp:

// https://godbolt.org/z/44KMf1fWr 
template<auto N>
constexpr auto fibonacci()    {
    if constexpr (N>=2) {
        return fibonacci<N-1>() + fibonacci<N-2>();
    } else {
        return N;
    }
}

int main() {
    std::cout << fibonacci<10>() << '\n';  // Ausgabe: 55
    std::cout << fibonacci<20>() << '\n';  // Ausgabe: 6765
}

Godbolt Listing lst-0356-godb.cpp, https://godbolt.org/z/44KMf1fWr:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/44KMf1fWr 
template<auto N>
constexpr auto fibonacci()    {
    if constexpr (N>=2) {
        return fibonacci<N-1>() + fibonacci<N-2>();
    } else {
        return N;
    }
}

int main() {
    std::cout << fibonacci<10>() << '\n';  // Ausgabe: 55
    std::cout << fibonacci<20>() << '\n';  // Ausgabe: 6765
}

Listing 13.17: Mit »consteval« können Sie Funktionen zur Übersetzungszeit ausführen lassen.

Book listing lst-0357-book.cpp:

// https://godbolt.org/z/8rr4WKo8d 
int hole_eingabe() {
    return 50; // oder lese was aus einer Datei oder so
}
constexpr auto berechne_1(int eingabe) {
    return eingabe * 2;
}
consteval auto berechne_2(int eingabe) {
    return eingabe * 2;
}
int main() {
    int eingabe = hole_eingabe();
    auto a = berechne_1(77);      // zur Übersetzungszeit ... vielleicht berechenbar
    auto b = berechne_1(eingabe); // … berechenbar, aber gültig
    auto c = berechne_2(77);      // … berechenbar
    auto d = berechne_2(eingabe); //                 (ERR)  … nicht berechenbar, ungültig
}

Godbolt Listing lst-0357-godb.cpp, https://godbolt.org/z/8rr4WKo8d:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8rr4WKo8d 
int hole_eingabe() {
    return 50; // oder lese was aus einer Datei oder so
}
constexpr auto berechne_1(int eingabe) {
    return eingabe * 2;
}
consteval auto berechne_2(int eingabe) {
    return eingabe * 2;
}
int main() {
    int eingabe = hole_eingabe();
    auto a = berechne_1(77);      // zur Übersetzungszeit ... vielleicht berechenbar
    auto b = berechne_1(eingabe); // … berechenbar, aber gültig
    auto c = berechne_2(77);      // … berechenbar
    auto d = berechne_2(eingabe); //                 (ERR)  … nicht berechenbar, ungültig
}

Listing 13.18: Auch komplexere Funktionen können mit »consteval« zur Übersetzungszeit berechnet werden.

Book listing lst-0358-book.cpp:

// https://godbolt.org/z/KGn9ob8on 
#include <iostream>
#include <array>
constexpr bool isPrime(int n) { // zur Übersetzungszeit berechenbar
  if(n < 2) return false; // 0, 1 sind nicht prim
  for (int i = 2; i*i <= n; i += i>2 ? 2 : 1) { // 2,3,5,7,9,11,13,15…
    if (n % i == 0) return false;
  }
  return n > 1; // für 0 und 1
}
template<int Num>
consteval std::array<int, Num> primeNumbers() { // nur zur Übersetzungszeit
  std::array<int, Num> primes{};
  int idx = 0;
  for (int val = 1; idx < Num; ++val) {
    if (isPrime(val)) primes[idx++] = val;
  }
  return primes;
}
int main() {
  // Initialisiere mit Primzahlen
  auto primes = primeNumbers<100>();  // 1000000 geht nicht
  for (auto v : primes) {
    std::cout << v << ' ';
  }
  std::cout << '\n';
}

Godbolt Listing lst-0358-godb.cpp, https://godbolt.org/z/KGn9ob8on:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KGn9ob8on 
#include <iostream>
#include <array>
constexpr bool isPrime(int n) { // zur Übersetzungszeit berechenbar
  if(n < 2) return false; // 0, 1 sind nicht prim
  for (int i = 2; i*i <= n; i += i>2 ? 2 : 1) { // 2,3,5,7,9,11,13,15…
    if (n % i == 0) return false;
  }
  return n > 1; // für 0 und 1
}
template<int Num>
consteval std::array<int, Num> primeNumbers() { // nur zur Übersetzungszeit
  std::array<int, Num> primes{};
  int idx = 0;
  for (int val = 1; idx < Num; ++val) {
    if (isPrime(val)) primes[idx++] = val;
  }
  return primes;
}
int main() {
  // Initialisiere mit Primzahlen
  auto primes = primeNumbers<100>();  // 1000000 geht nicht
  for (auto v : primes) {
    std::cout << v << ' ';
  }
  std::cout << '\n';
}

Listing 13.19: Der Compiler stellt fest, ob der Aufruf im Context zur Compilezeit berechnet werden kann.

Book listing lst-0359-book.cpp:

// https://godbolt.org/z/7KWqTPo1K 
#include <iostream> // cout
constexpr int hole_wert() {
    if consteval {
       return 42;
    } else {
       return 668;
    }
}
int main() {
  auto a = hole_wert();
  std::cout << a << '\n';       // Ausgabe: 668
  constexpr auto b = hole_wert();
  std::cout << b << '\n';       // Ausgabe: 42
}

Godbolt Listing lst-0359-godb.cpp, https://godbolt.org/z/7KWqTPo1K:

//#(compile) c++; compiler:g132; options:"-std=c++23"; libs:-
// https://godbolt.org/z/7KWqTPo1K 
#include <iostream> // cout
constexpr int hole_wert() {
    if consteval {
       return 42;
    } else {
       return 668;
    }
}
int main() {
  auto a = hole_wert();
  std::cout << a << '\n';       // Ausgabe: 668
  constexpr auto b = hole_wert();
  std::cout << b << '\n';       // Ausgabe: 42
}

Listing 13.20: »mutable« macht ein Datenfeld in const-Methoden veränderbar.

Book listing lst-0361-book.cpp:

// https://godbolt.org/z/sPorKnEbd 
#include <iostream>
class Data {
    int value_;
    mutable size_t getCount_{0};
  public:
    explicit Data(int v) : value_{v} { }
    ~Data() {
        std::cout << "get wurde " << getCount_ << "-mal benutzt\n";
    }
    int get() const {
        ++getCount_;
        return value_;
    }
};
int main() {
    Data d{42};
    for(int i=0; i<10; ++i) { d.get(); }
} // Ausgabe: get wurde 10-mal benutzt

Godbolt Listing lst-0361-godb.cpp, https://godbolt.org/z/sPorKnEbd:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sPorKnEbd 
#include <iostream>
class Data {
    int value_;
    mutable size_t getCount_{0};
  public:
    explicit Data(int v) : value_{v} { }
    ~Data() {
        std::cout << "get wurde " << getCount_ << "-mal benutzt\n";
    }
    int get() const {
        ++getCount_;
        return value_;
    }
};
int main() {
    Data d{42};
    for(int i=0; i<10; ++i) { d.get(); }
} // Ausgabe: get wurde 10-mal benutzt

Listing 13.21: »const« mit Containern

Book listing lst-0362-book.cpp:

// https://godbolt.org/z/GE5v6Ea8x 
#include <map>
#include <string>
using std::map; using std::string;
struct MyClass {
  bool isFound(const map<int,string> &dict,  // unveränderbarer Eingabeparam.
               const int &key,               // ebenso
               string &result                // Ausgabeparameter: kein const
               ) const                       // Instanz von MyClass const
  {
    const map<int,string>::const_iterator where  // Verweis und Wert fest
      = dict.find(key);
    if(where == end(dict)) {
      return false;
    } else {
      result = where->second;
      return true;
    }
  }
};

Godbolt Listing lst-0362-godb.cpp, https://godbolt.org/z/GE5v6Ea8x:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/GE5v6Ea8x 
#include <map>
#include <string>
using std::map; using std::string;
struct MyClass {
  bool isFound(const map<int,string> &dict,  // unveränderbarer Eingabeparam.
               const int &key,               // ebenso
               string &result                // Ausgabeparameter: kein const
               ) const                       // Instanz von MyClass const
  {
    const map<int,string>::const_iterator where  // Verweis und Wert fest
      = dict.find(key);
    if(where == end(dict)) {
      return false;
    } else {
      result = where->second;
      return true;
    }
  }
};

Listing 13.22: x und y können irgendwie von außen verändert werden.

Book listing lst-0363-book.cpp:

#include <iostream>
#include <chrono> // milliseconds
#include <thread> // this_thread::sleep

struct Pos {
  volatile int x;
  volatile int y;
};
Pos pos{};

// irgendwo anders definiert:
int installMouseDriver(Pos *p);

constexpr auto DELAY = std::chrono::milliseconds(100);
constexpr auto LOOPS = 30; // 30*100ms = 3s
int main() {
    installMouseDriver( &pos );  // MouseDriver aktualisiert x und y
    for(int i=0; i<LOOPS; ++i) {
        std::cout << "maus bei ("<<pos.x<<","<<pos.y<<")\n";
        std::this_thread::sleep_for(DELAY);
    }
}

Listing 14.1: Solitäre Tests testen nur eine Komponente, Helferklassen werden untergeschoben.

Book listing lst-0364-book.cpp:

// https://godbolt.org/z/a83sf9h8E 
#include <iostream>
// Produktionscode:
struct DatabaseInterface {
    virtual int getData() const = 0;
};
struct Programm {
    DatabaseInterface &db_;
    void run() {
        std:: cout << db_.getData() << "\n";
    }
};
// Testhelfer:
struct MockDatabase : public DatabaseInterface {
    int getData() const override { return 5; }
};
// main als Test:
int main() {
    MockDatabase mockDb;
    Programm prog { mockDb }; // echte DB wird nicht mitgetestet
    prog.run();               // Erwartete Ausgabe: 5
}

Godbolt Listing lst-0364-godb.cpp, https://godbolt.org/z/a83sf9h8E:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a83sf9h8E 
#include <iostream>
// Produktionscode:
struct DatabaseInterface {
    virtual int getData() const = 0;
};
struct Programm {
    DatabaseInterface &db_;
    void run() {
        std:: cout << db_.getData() << "\n";
    }
};
// Testhelfer:
struct MockDatabase : public DatabaseInterface {
    int getData() const override { return 5; }
};
// main als Test:
int main() {
    MockDatabase mockDb;
    Programm prog { mockDb }; // echte DB wird nicht mitgetestet
    prog.run();               // Erwartete Ausgabe: 5
}

Listing 14.2: Soziale Tests testen das Zusammenspiel der Komponenten mit.

Book listing lst-0365-book.cpp:

// https://godbolt.org/z/fsroE4seh 
#include <iostream>

// Produktionscode:
struct DatabaseInterface {
    virtual int getData() const = 0;
};
struct RealDatabase : public DatabaseInterface {
    int getData() const override { return 999; }
};
struct Programm {
    DatabaseInterface &db_;
    void run() {
        std:: cout << db_.getData() << "\n";
    }
};

// main als Test:
int main() {
    RealDatabase db;
    Programm prog { db }; // echte DB wird  mitgetestet
    prog.run();           // Erwartete Ausgabe: 999
}

Godbolt Listing lst-0365-godb.cpp, https://godbolt.org/z/fsroE4seh:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fsroE4seh 
#include <iostream>

// Produktionscode:
struct DatabaseInterface {
    virtual int getData() const = 0;
};
struct RealDatabase : public DatabaseInterface {
    int getData() const override { return 999; }
};
struct Programm {
    DatabaseInterface &db_;
    void run() {
        std:: cout << db_.getData() << "\n";
    }
};

// main als Test:
int main() {
    RealDatabase db;
    Programm prog { db }; // echte DB wird  mitgetestet
    prog.run();           // Erwartete Ausgabe: 999
}

GodboltId:4PeYrc8jo

Book listing lst-0366-book.cpp:

// https://godbolt.org/z/4PeYrc8jo 
void testVerdopple5() {
    // vorbereiten
    auto param = 5;
    // ausführen
    auto result = verdopple(param);
    // überprüfen
    assertTrue(result == 10);
}

Godbolt Listing lst-0366-godb.cpp, https://godbolt.org/z/4PeYrc8jo:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4PeYrc8jo 
void testVerdopple5() {
    // vorbereiten
    auto param = 5;
    // ausführen
    auto result = verdopple(param);
    // überprüfen
    assertTrue(result == 10);
}

GodboltId:Y9exe7rqT

Book listing lst-0367-book.cpp:

// https://godbolt.org/z/Y9exe7rqT 
void testVerdopple() {
    assertTrue( verdopple(0) == 0 );
    assertTrue( verdopple(-1) == -2 );
    assertTrue( verdopple(1) == 2 );
    assertTrue( verdopple(5) == 10 );
}

Godbolt Listing lst-0367-godb.cpp, https://godbolt.org/z/Y9exe7rqT:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Y9exe7rqT 
void testVerdopple() {
    assertTrue( verdopple(0) == 0 );
    assertTrue( verdopple(-1) == -2 );
    assertTrue( verdopple(1) == 2 );
    assertTrue( verdopple(5) == 10 );
}

Listing 14.3: In der Datei »fib.cpp« ist eine freie Funktion, die Sie testen wollen.

Book listing lst-0368-book.cpp:

// https://godbolt.org/z/Ex6Mv6xcz 
unsigned fib(unsigned n) {
    if(n==0) { return 0; }
    if(n==1) { return 1; }
    unsigned a = 0;
    unsigned b = 1;
    unsigned sum = 1;
    while(n>1) {
        sum += a;
        a = b;
        b = sum;
        n -= 1;
    }
    return sum;
}

Godbolt Listing lst-0368-godb.cpp, https://godbolt.org/z/Ex6Mv6xcz:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Ex6Mv6xcz 
unsigned fib(unsigned n) {
    if(n==0) { return 0; }
    if(n==1) { return 1; }
    unsigned a = 0;
    unsigned b = 1;
    unsigned sum = 1;
    while(n>1) {
        sum += a;
        a = b;
        b = sum;
        n -= 1;
    }
    return sum;
}

GodboltId:ba7e7s8qK

Book listing lst-0369-book.cpp:

// https://godbolt.org/z/ba7e7s8qK 
#define BOOST_TEST_MAIN test_main            // generiert main() in diesem Modul
#include <boost/test/included/unit_test.hpp> // Framework
#include <boost/test/test_tools.hpp>         // BOOST_CHECK etc
unsigned fib(unsigned n);                    // zu testen
namespace {
using namespace boost::unit_test;
BOOST_AUTO_TEST_CASE( test_fib_low )         // beliebiger Name des Testcases
{
    BOOST_CHECK( fib(0) == 0 );              // einzelne Assertions
    BOOST_CHECK( fib(1) == 1 );
    BOOST_CHECK( fib(2) == 1 );
    BOOST_CHECK( fib(3) == 2 );
    BOOST_CHECK( fib(4) == 3 );
    BOOST_CHECK( fib(5) == 5 );
    BOOST_CHECK( fib(6) == 8 );
}
}

Godbolt Listing lst-0369-godb.cpp, https://godbolt.org/z/ba7e7s8qK:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ba7e7s8qK 
#define BOOST_TEST_MAIN test_main            // generiert main() in diesem Modul
#include <boost/test/included/unit_test.hpp> // Framework
#include <boost/test/test_tools.hpp>         // BOOST_CHECK etc
unsigned fib(unsigned n);                    // zu testen
namespace {
using namespace boost::unit_test;
BOOST_AUTO_TEST_CASE( test_fib_low )         // beliebiger Name des Testcases
{
    BOOST_CHECK( fib(0) == 0 );              // einzelne Assertions
    BOOST_CHECK( fib(1) == 1 );
    BOOST_CHECK( fib(2) == 1 );
    BOOST_CHECK( fib(3) == 2 );
    BOOST_CHECK( fib(4) == 3 );
    BOOST_CHECK( fib(5) == 5 );
    BOOST_CHECK( fib(6) == 8 );
}
}

Listing 14.4: Die Haupt-Headerdatei der Bibliothek qwort.hpp

Book listing lst-0375-book.cpp:

// https://godbolt.org/z/5ajrvGvcW 
#ifndef QWORT_H   // Header-Guard
#define QWORT_H
#include <string>
#include <string_view>
#include <memory> // unique_ptr
namespace qw {    // Namensraum der Bibliothek

    int version();

    namespace impl_multimap {
        class index_impl;
    }

    class index {
        using index_impl = impl_multimap::index_impl;
    public:
        index();
        ~index() noexcept; // wird für pimpl benötigt
        index(const index&) = delete;
        index(index&&) noexcept;
        index& operator=(const index&) = delete;
        index& operator=(index&&) = delete;
    public:
        void add(std::string_view arg);
        size_t size() const;
        std::string getBestMatch(std::string_view query) const;
    public:          // public für Tests
        std::string normalize(std::string arg) const;
    private:
        std::unique_ptr<index_impl> pimpl;
    };
} // namespace qw
#endif // Header-Guard

Godbolt Listing lst-0375-godb.cpp, https://godbolt.org/z/5ajrvGvcW:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5ajrvGvcW 
#ifndef QWORT_H   // Header-Guard
#define QWORT_H
#include <string>
#include <string_view>
#include <memory> // unique_ptr
namespace qw {    // Namensraum der Bibliothek

    int version();

    namespace impl_multimap {
        class index_impl;
    }

    class index {
        using index_impl = impl_multimap::index_impl;
    public:
        index();
        ~index() noexcept; // wird für pimpl benötigt
        index(const index&) = delete;
        index(index&&) noexcept;
        index& operator=(const index&) = delete;
        index& operator=(index&&) = delete;
    public:
        void add(std::string_view arg);
        size_t size() const;
        std::string getBestMatch(std::string_view query) const;
    public:          // public für Tests
        std::string normalize(std::string arg) const;
    private:
        std::unique_ptr<index_impl> pimpl;
    };
} // namespace qw
#endif // Header-Guard

Listing 14.5: Öffentliche Schnittstelle nur fürs Testen

Book listing lst-0376-book.cpp:

class index_impl {
// ...
public: // test interface
    vector<string> _qgramify(string_view n) const { return qgramify(n); }
    static size_t _q() { return Q; }
    static std::string _prefix() { return PREFIX; }
    static std::string _suffix() { return SUFFIX; }
};

Listing 14.6: Dieses Testmodul testet qwort.cpp.

Book listing lst-0377-book.cpp:

// https://godbolt.org/z/Y98jq1eGx 
#include "qwort/qwort.hpp" // under test
#define BOOST_TEST_MODULE qwort
#include <boost/test/included/unit_test.hpp>
using namespace boost::unit_test;
BOOST_AUTO_TEST_CASE( version_is_1 ) {
    BOOST_TEST(qw::version() == 1);
    // der folgende Vergleich soll fehlschlagen, aber nur eine Warnung erzeugen:
    BOOST_WARN_EQUAL(qw::version(), 2);   //                 (ERR)  ungleich, aber macht weiter
}
BOOST_AUTO_TEST_CASE( init_size_0 ) {
    qw::index inst{};                     // arrange
    auto sz = inst.size();                // act
    BOOST_TEST(sz == 0u);                 // assert
}
BOOST_AUTO_TEST_CASE( add_size_1 ) {
    using namespace std::literals::string_literals;
    qw::index inst{};                     // arrange
    inst.add(""s);                        // act
    BOOST_REQUIRE_EQUAL(inst.size(), 1u); // assert
}
BOOST_AUTO_TEST_CASE( normalize ) {
    using namespace std::literals::string_literals;
    qw::index inst{}; // arrange
    // acts und asserts; könnte auch in getrennten Funktionen sein
    BOOST_CHECK_EQUAL(inst.normalize("a"s), "A"s);
    BOOST_CHECK_EQUAL(inst.normalize("Stadt"s), "STADT"s);
    BOOST_CHECK_EQUAL(inst.normalize("Leer Zeichen"s), "LEER#ZEICHEN"s);
    BOOST_CHECK_EQUAL(inst.normalize("!Sym-bol."s), "#SYM#BOL#"s);
}
BOOST_AUTO_TEST_CASE( move ) {
    qw::index inst{};
    qw::index other = std::move( inst );
    BOOST_CHECK_EQUAL(other.size(), 0u); // pimpl erfolgreich verschoben?
}

Godbolt Listing lst-0377-godb.cpp, https://godbolt.org/z/Y98jq1eGx:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Y98jq1eGx 
#include "qwort/qwort.hpp" // under test
#define BOOST_TEST_MODULE qwort
#include <boost/test/included/unit_test.hpp>
using namespace boost::unit_test;
BOOST_AUTO_TEST_CASE( version_is_1 ) {
    BOOST_TEST(qw::version() == 1);
    // der folgende Vergleich soll fehlschlagen, aber nur eine Warnung erzeugen:
    BOOST_WARN_EQUAL(qw::version(), 2);   //                 (ERR)  ungleich, aber macht weiter
}
BOOST_AUTO_TEST_CASE( init_size_0 ) {
    qw::index inst{};                     // arrange
    auto sz = inst.size();                // act
    BOOST_TEST(sz == 0u);                 // assert
}
BOOST_AUTO_TEST_CASE( add_size_1 ) {
    using namespace std::literals::string_literals;
    qw::index inst{};                     // arrange
    inst.add(""s);                        // act
    BOOST_REQUIRE_EQUAL(inst.size(), 1u); // assert
}
BOOST_AUTO_TEST_CASE( normalize ) {
    using namespace std::literals::string_literals;
    qw::index inst{}; // arrange
    // acts und asserts; könnte auch in getrennten Funktionen sein
    BOOST_CHECK_EQUAL(inst.normalize("a"s), "A"s);
    BOOST_CHECK_EQUAL(inst.normalize("Stadt"s), "STADT"s);
    BOOST_CHECK_EQUAL(inst.normalize("Leer Zeichen"s), "LEER#ZEICHEN"s);
    BOOST_CHECK_EQUAL(inst.normalize("!Sym-bol."s), "#SYM#BOL#"s);
}
BOOST_AUTO_TEST_CASE( move ) {
    qw::index inst{};
    qw::index other = std::move( inst );
    BOOST_CHECK_EQUAL(other.size(), 0u); // pimpl erfolgreich verschoben?
}

Listing 14.7: Hier wird die Testsuite manuell zusammengebaut.

Book listing lst-0387-book.cpp:

// https://godbolt.org/z/TfMnK1Tnn 
/* private Header aus lib-Verzeichnis: */
#include "impl_multimap.hpp"                  // zu testen
// wir definieren  init_unit_test_suite() selbst, also NICHT setzen:
/* #define BOOST_TEST_MODULE qgram */
#include <boost/test/included/unit_test.hpp>
#include <memory>                             // shared ptr
#include <vector>
#include <string>
using namespace boost::unit_test;
using namespace std::literals::string_literals;
using std::string; using std::vector;
/* === Eine Testklasse für die zu testende Klasse === */
using UnderTest = qw::impl_multimap::index_impl;
class ImplMultimapTest {                      // Klasse mit Testmethoden
public:
    /* === Konstanten === */
    void testConstants() {
        BOOST_REQUIRE_EQUAL(UnderTest::_prefix().length(), UnderTest::_q()-1);
        BOOST_REQUIRE_EQUAL(UnderTest::_suffix().length(), UnderTest::_q()-1);
        for(size_t i = 0; i < UnderTest::_q()-1; ++i) {
            BOOST_CHECK_EQUAL(UnderTest::_prefix()[i], '^');
            BOOST_CHECK_EQUAL(UnderTest::_suffix()[i], '$');
        }
        // oder konkreter:
        BOOST_TEST(UnderTest::_q() == 3u);
        BOOST_TEST(UnderTest::_prefix() == "^^"s);
        BOOST_TEST(UnderTest::_suffix() == "$$"s);
    }
    /* === qgramify === */
    void testQgramifyEmpty() {
        UnderTest inst{};
        auto result = inst._qgramify(""s);
        vector<string> expected{"^^$"s, "^$$"s};
        BOOST_CHECK_EQUAL_COLLECTIONS(
            result.begin(), result.end(), expected.begin(), expected.end() );
    }
    void testQgramify1() {
        UnderTest inst{};
        auto result = inst._qgramify("a"s);
        vector<string> expected{"^^a"s, "^a$"s, "a$$"s};
        BOOST_CHECK_EQUAL_COLLECTIONS(
            result.begin(), result.end(), expected.begin(), expected.end() );
    }
    void testQgramify2() {
        UnderTest inst{};
        auto result = inst._qgramify("ab"s);
        vector<string> expected{"^^a"s, "^ab"s, "ab$"s, "b$$"s};
        BOOST_CHECK_EQUAL_COLLECTIONS(
            result.begin(), result.end(), expected.begin(), expected.end() );
    }
    void testQgramify3() {
        UnderTest inst{};
        auto result = inst._qgramify("abc"s);
        vector<string> expected{"^^a"s, "^ab"s, "abc"s, "bc$"s, "c$$"s};
        BOOST_CHECK_EQUAL_COLLECTIONS(
            result.begin(), result.end(), expected.begin(), expected.end() );
    }
    /* === add === */
    void testAdd_nodups() {
        UnderTest inst{};                     /* arrange */
        BOOST_REQUIRE_EQUAL(inst.size(), 0u); /* assert */
        inst.add("", "");                     /* act */
        BOOST_CHECK_EQUAL(inst.size(), 1u);   /* assert */
        inst.add("ENTRY", "entry");           /* act */
        BOOST_CHECK_EQUAL(inst.size(), 2u);   /* assert */
        inst.add("OTHER", "other");           /* act */
        BOOST_CHECK_EQUAL(inst.size(), 3u);   /* assert */
    }
    /* === add === */
    void test_getBestMatch_empty() {
        UnderTest inst{};
        auto result = inst.getBestMatch("any");
        BOOST_CHECK_EQUAL(result, ""s);
    }
    void test_getBestMatch_one() {
        /* arrange */
        UnderTest inst{};
        inst.add("HOLSDERTEUFEL", "holsderteufel");
        /* act */
        auto result = inst.getBestMatch("ROBERT");
        BOOST_CHECK_EQUAL(result, "holsderteufel"s);
    }
    void test_getBestMatch_exact() {
        /* arrange */
        UnderTest inst{};
        inst.add("BERLIN", "Berlin");
        inst.add("HAMBURG", "Hamburg");
        inst.add("DORTMUND", "Dortmund");
        inst.add("STUTTGART", "Stuttgart");
        inst.add("WYK", "Wyk");
        /* act and assert */
        BOOST_CHECK_EQUAL(inst.getBestMatch("BERLIN"), "Berlin"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("HAMBURG"), "Hamburg"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("DORTMUND"), "Dortmund"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("STUTTGART"), "Stuttgart"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("WYK"), "Wyk"s);
    }
    void test_getBestMatch_close() {
        /* arrange */
        UnderTest inst{};
        inst.add("BERLIN", "Berlin");
        inst.add("HAMBURG", "Hamburg");
        inst.add("DORTMUND", "Dortmund");
        inst.add("STUTTGART", "Stuttgart");
        inst.add("WYK", "Wyk");
        /* act and assert */
        BOOST_CHECK_EQUAL(inst.getBestMatch("BRLIN"), "Berlin"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("BURG"), "Hamburg"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("DORTDORT"), "Dortmund"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("STUTGURT"), "Stuttgart"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("WIK"), "Wyk"s);
    }
/* Bei neuen Testmethoden: Hinzufügen zu init_unit_test_suite() nicht vergessen */
};
/* === Suite === */
test_suite* init_unit_test_suite( int argc, char* argv[] ) {
    auto tester = std::make_shared<ImplMultimapTest>();
    auto &ts = framework::master_test_suite();
    ts.add( BOOST_TEST_CASE( [=](){ tester->testConstants(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramifyEmpty(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify1(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify2(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify3(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify3(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->testAdd_nodups(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_empty(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_one(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_exact(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_close(); } ));
    return nullptr;
}

Godbolt Listing lst-0387-godb.cpp, https://godbolt.org/z/TfMnK1Tnn:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TfMnK1Tnn 
/* private Header aus lib-Verzeichnis: */
#include "impl_multimap.hpp"                  // zu testen
// wir definieren  init_unit_test_suite() selbst, also NICHT setzen:
/* #define BOOST_TEST_MODULE qgram */
#include <boost/test/included/unit_test.hpp>
#include <memory>                             // shared ptr
#include <vector>
#include <string>
using namespace boost::unit_test;
using namespace std::literals::string_literals;
using std::string; using std::vector;
/* === Eine Testklasse für die zu testende Klasse === */
using UnderTest = qw::impl_multimap::index_impl;
class ImplMultimapTest {                      // Klasse mit Testmethoden
public:
    /* === Konstanten === */
    void testConstants() {
        BOOST_REQUIRE_EQUAL(UnderTest::_prefix().length(), UnderTest::_q()-1);
        BOOST_REQUIRE_EQUAL(UnderTest::_suffix().length(), UnderTest::_q()-1);
        for(size_t i = 0; i < UnderTest::_q()-1; ++i) {
            BOOST_CHECK_EQUAL(UnderTest::_prefix()[i], '^');
            BOOST_CHECK_EQUAL(UnderTest::_suffix()[i], '$');
        }
        // oder konkreter:
        BOOST_TEST(UnderTest::_q() == 3u);
        BOOST_TEST(UnderTest::_prefix() == "^^"s);
        BOOST_TEST(UnderTest::_suffix() == "$$"s);
    }
    /* === qgramify === */
    void testQgramifyEmpty() {
        UnderTest inst{};
        auto result = inst._qgramify(""s);
        vector<string> expected{"^^$"s, "^$$"s};
        BOOST_CHECK_EQUAL_COLLECTIONS(
            result.begin(), result.end(), expected.begin(), expected.end() );
    }
    void testQgramify1() {
        UnderTest inst{};
        auto result = inst._qgramify("a"s);
        vector<string> expected{"^^a"s, "^a$"s, "a$$"s};
        BOOST_CHECK_EQUAL_COLLECTIONS(
            result.begin(), result.end(), expected.begin(), expected.end() );
    }
    void testQgramify2() {
        UnderTest inst{};
        auto result = inst._qgramify("ab"s);
        vector<string> expected{"^^a"s, "^ab"s, "ab$"s, "b$$"s};
        BOOST_CHECK_EQUAL_COLLECTIONS(
            result.begin(), result.end(), expected.begin(), expected.end() );
    }
    void testQgramify3() {
        UnderTest inst{};
        auto result = inst._qgramify("abc"s);
        vector<string> expected{"^^a"s, "^ab"s, "abc"s, "bc$"s, "c$$"s};
        BOOST_CHECK_EQUAL_COLLECTIONS(
            result.begin(), result.end(), expected.begin(), expected.end() );
    }
    /* === add === */
    void testAdd_nodups() {
        UnderTest inst{};                     /* arrange */
        BOOST_REQUIRE_EQUAL(inst.size(), 0u); /* assert */
        inst.add("", "");                     /* act */
        BOOST_CHECK_EQUAL(inst.size(), 1u);   /* assert */
        inst.add("ENTRY", "entry");           /* act */
        BOOST_CHECK_EQUAL(inst.size(), 2u);   /* assert */
        inst.add("OTHER", "other");           /* act */
        BOOST_CHECK_EQUAL(inst.size(), 3u);   /* assert */
    }
    /* === add === */
    void test_getBestMatch_empty() {
        UnderTest inst{};
        auto result = inst.getBestMatch("any");
        BOOST_CHECK_EQUAL(result, ""s);
    }
    void test_getBestMatch_one() {
        /* arrange */
        UnderTest inst{};
        inst.add("HOLSDERTEUFEL", "holsderteufel");
        /* act */
        auto result = inst.getBestMatch("ROBERT");
        BOOST_CHECK_EQUAL(result, "holsderteufel"s);
    }
    void test_getBestMatch_exact() {
        /* arrange */
        UnderTest inst{};
        inst.add("BERLIN", "Berlin");
        inst.add("HAMBURG", "Hamburg");
        inst.add("DORTMUND", "Dortmund");
        inst.add("STUTTGART", "Stuttgart");
        inst.add("WYK", "Wyk");
        /* act and assert */
        BOOST_CHECK_EQUAL(inst.getBestMatch("BERLIN"), "Berlin"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("HAMBURG"), "Hamburg"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("DORTMUND"), "Dortmund"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("STUTTGART"), "Stuttgart"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("WYK"), "Wyk"s);
    }
    void test_getBestMatch_close() {
        /* arrange */
        UnderTest inst{};
        inst.add("BERLIN", "Berlin");
        inst.add("HAMBURG", "Hamburg");
        inst.add("DORTMUND", "Dortmund");
        inst.add("STUTTGART", "Stuttgart");
        inst.add("WYK", "Wyk");
        /* act and assert */
        BOOST_CHECK_EQUAL(inst.getBestMatch("BRLIN"), "Berlin"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("BURG"), "Hamburg"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("DORTDORT"), "Dortmund"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("STUTGURT"), "Stuttgart"s);
        BOOST_CHECK_EQUAL(inst.getBestMatch("WIK"), "Wyk"s);
    }
/* Bei neuen Testmethoden: Hinzufügen zu init_unit_test_suite() nicht vergessen */
};
/* === Suite === */
test_suite* init_unit_test_suite( int argc, char* argv[] ) {
    auto tester = std::make_shared<ImplMultimapTest>();
    auto &ts = framework::master_test_suite();
    ts.add( BOOST_TEST_CASE( [=](){ tester->testConstants(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramifyEmpty(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify1(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify2(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify3(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->testQgramify3(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->testAdd_nodups(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_empty(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_one(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_exact(); } ));
    ts.add( BOOST_TEST_CASE( [=](){ tester->test_getBestMatch_close(); } ));
    return nullptr;
}

Listing 14.8: Eine Testfunktion mit einem Parameter kann mit Testdaten aufgerufen werden.

Book listing lst-0392-book.cpp:

// https://godbolt.org/z/q8E6WMano 
#include <boost/test/parameterized_test.hpp>
struct Param {
    string input;
    vector<string> expected;
};
const vector<Param> params {
    // { Eingabe, erwartetes Ergebnis }
    {""s,     {"^^$"s, "^$$"s} },
    {"A"s,    {"^^A"s, "^A$"s, "A$$"s} },
    {"AB"s,   {"^^A"s, "^AB"s, "AB$"s, "B$$"s} },
    {"ACB"s,  {"^^A"s, "^AC"s, "ACB"s, "CB$"s, "B$$"s} },
    {"AAA"s,  {"^^A"s, "^AA"s, "AAA"s, "AA$"s, "A$$"s} },
};
void testQgramify(const Param& param) {
    /* arrange */
    UnderTest inst{};
    /* act */
    auto result = inst._qgramify(param.input);
    /* assert */
    BOOST_CHECK_EQUAL_COLLECTIONS(
        param.expected.begin(), param.expected.end(),
        result.begin(), result.end());
}

Godbolt Listing lst-0392-godb.cpp, https://godbolt.org/z/q8E6WMano:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/q8E6WMano 
#include <boost/test/parameterized_test.hpp>
struct Param {
    string input;
    vector<string> expected;
};
const vector<Param> params {
    // { Eingabe, erwartetes Ergebnis }
    {""s,     {"^^$"s, "^$$"s} },
    {"A"s,    {"^^A"s, "^A$"s, "A$$"s} },
    {"AB"s,   {"^^A"s, "^AB"s, "AB$"s, "B$$"s} },
    {"ACB"s,  {"^^A"s, "^AC"s, "ACB"s, "CB$"s, "B$$"s} },
    {"AAA"s,  {"^^A"s, "^AA"s, "AAA"s, "AA$"s, "A$$"s} },
};
void testQgramify(const Param& param) {
    /* arrange */
    UnderTest inst{};
    /* act */
    auto result = inst._qgramify(param.input);
    /* assert */
    BOOST_CHECK_EQUAL_COLLECTIONS(
        param.expected.begin(), param.expected.end(),
        result.begin(), result.end());
}

Listing 15.1: Der gemeinsame Vorfahre unserer Hilfsklassen »Year«, »Month« und »Day«

Book listing lst-0398-book.cpp:

// https://godbolt.org/z/hhGo46z5a 
#include <iostream>  // ostream
#include <format>    // format, vformat, make_format_args
using std::ostream;
class Value {
protected: // nicht öffentlich, nur für den eigenen und abgeleiteten Gebrauch
    int value_;
    const std::string fmt_;  // z. B. "{:02}" oder "{:04}"
    Value(int v, unsigned w) // Konstruktor mit zwei Argumenten
      : value_{v}, fmt_{std::format("{{:0{}}}", w)} {}
public:
    ostream& print(ostream& os) const;
};
ostream& operator<<(ostream& os, const Value& rechts) {
    return rechts.print(os);
}
ostream& Value::print(ostream& os) const {
    return os << std::vformat(fmt_, std::make_format_args(value_));
}

Godbolt Listing lst-0398-godb.cpp, https://godbolt.org/z/hhGo46z5a:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hhGo46z5a 
#include <iostream>  // ostream
#include <format>    // format, vformat, make_format_args
using std::ostream;
class Value {
protected: // nicht öffentlich, nur für den eigenen und abgeleiteten Gebrauch
    int value_;
    const std::string fmt_;  // z. B. "{:02}" oder "{:04}"
    Value(int v, unsigned w) // Konstruktor mit zwei Argumenten
      : value_{v}, fmt_{std::format("{{:0{}}}", w)} {}
public:
    ostream& print(ostream& os) const;
};
ostream& operator<<(ostream& os, const Value& rechts) {
    return rechts.print(os);
}
ostream& Value::print(ostream& os) const {
    return os << std::vformat(fmt_, std::make_format_args(value_));
}

Listing 15.2: Der doppelte Code der Hilfsklassen ist nun verschwunden.

Book listing lst-0399-book.cpp:

// https://godbolt.org/z/eYY1js4Te 
class Year : public Value {               // von Klasse Value ableiten
public:
    explicit Year(int v) : Value{v, 4} {} // Basisklasse initialisieren
};
class Month : public Value {
public:
    explicit Month(int v) : Value{v, 2} {}
};
struct Day : public Value {               // class-public entspricht struct
    explicit Day(int v) : Value{v, 2} {}
};

Godbolt Listing lst-0399-godb.cpp, https://godbolt.org/z/eYY1js4Te:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eYY1js4Te 
class Year : public Value {               // von Klasse Value ableiten
public:
    explicit Year(int v) : Value{v, 4} {} // Basisklasse initialisieren
};
class Month : public Value {
public:
    explicit Month(int v) : Value{v, 2} {}
};
struct Day : public Value {               // class-public entspricht struct
    explicit Day(int v) : Value{v, 2} {}
};

Listing 15.3: So verwendet »Date« die neuen Klassen.

Book listing lst-0400-book.cpp:

// https://godbolt.org/z/9rY7qhK89 
class Date {
    Year year_;
    Month month_ {1};
    Day day_ {1};
public:
    explicit Date(int y) : year_{y} {} // year-01-01
    Date(Year y, Month m, Day d) : year_{y}, month_{m}, day_{d} {}
    ostream& print(ostream& os) const;
};
ostream& Date::print(ostream& os) const {
    return os << year_ << "-" << month_ << "-"  << day_;
}
ostream& operator<<(ostream& os, const Date& rechts) {
    return rechts.print(os);
}
int main() {
    Date d1 { Year{2013}, Month{15}, Day{19} };
    std::cout << d1 << "\n"; // Ausgabe: 2013-15-19
}

Godbolt Listing lst-0400-godb.cpp, https://godbolt.org/z/9rY7qhK89:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9rY7qhK89 
class Date {
    Year year_;
    Month month_ {1};
    Day day_ {1};
public:
    explicit Date(int y) : year_{y} {} // year-01-01
    Date(Year y, Month m, Day d) : year_{y}, month_{m}, day_{d} {}
    ostream& print(ostream& os) const;
};
ostream& Date::print(ostream& os) const {
    return os << year_ << "-" << month_ << "-"  << day_;
}
ostream& operator<<(ostream& os, const Date& rechts) {
    return rechts.print(os);
}
int main() {
    Date d1 { Year{2013}, Month{15}, Day{19} };
    std::cout << d1 << "\n"; // Ausgabe: 2013-15-19
}

Listing 15.4: Nun ist »ostern« eine Methode von »Year«.

Book listing lst-0401-book.cpp:

// https://godbolt.org/z/Wjsvv6Gdv 
class Date;  // Vorwärtsdeklaration
class Year : public Value {
public:
    explicit Year(int v) : Value{v, 4} {}
    Date ostern() const;            // neue Methode deklarieren
};
// Hier Month, Day und Date deklarieren. Dann:
Date Year::ostern() const {         // neue Methode definieren
    const int y = value_;
    int a = value_/100*1483 - value_/400*2225 + 2613;
    int b = (value_%19*3510 + a/25*319)/330%29;
    b = 148 - b - (value_*5/4 + a - b)%7;
    return Date{Year{value_}, Month{b/31}, Day{b%31 + 1}};
}
int main() {
    using std::cout;
    Year year{2014};
    cout << year.ostern() << "\n";  // Ausgabe: 2014-04-20
}

Godbolt Listing lst-0401-godb.cpp, https://godbolt.org/z/Wjsvv6Gdv:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Wjsvv6Gdv 
class Date;  // Vorwärtsdeklaration
class Year : public Value {
public:
    explicit Year(int v) : Value{v, 4} {}
    Date ostern() const;            // neue Methode deklarieren
};
// Hier Month, Day und Date deklarieren. Dann:
Date Year::ostern() const {         // neue Methode definieren
    const int y = value_;
    int a = value_/100*1483 - value_/400*2225 + 2613;
    int b = (value_%19*3510 + a/25*319)/330%29;
    b = 148 - b - (value_*5/4 + a - b)%7;
    return Date{Year{value_}, Month{b/31}, Day{b%31 + 1}};
}
int main() {
    using std::cout;
    Year year{2014};
    cout << year.ostern() << "\n";  // Ausgabe: 2014-04-20
}

Listing 15.5: Alle Komponenten haben eine weiße Farbe, nur der Druckknopf wird grau.

Book listing lst-0402-book.cpp:

struct Komponente {
    Color getColor() const { return weiss; }
};
struct Fenster : public Komponente { };
struct Hauptfenster : public Fenster { };
struct Dialog : public Fenster { };
struct Texteingabe : public Komponente { };
struct Druckknopf : public Komponente {
    Color getColor() const  { return grau; }
};

Listing 15.6: Was gibt »print« aus? Die Methode »wert« kommt öfter vor.

Book listing lst-0403-book.cpp:

// https://godbolt.org/z/476G1xzKr 
#include <iostream>
struct Basis {
    int acht_ = 8;
    int wert() const { return acht_; }
    void print(std::ostream& os) const { os << wert() << "\n"; }
};
struct Print : public Basis {
    int neun_ = 9;
    void print(std::ostream& os) const { os << wert() << "\n"; }
};
struct Wert : public Basis {
    int zehn_ = 10;
    int wert() const { return zehn_; }
};
struct Beides : public Basis {
    int elf_ = 11;
    int wert() const { return elf_; }
    void print(std::ostream& os) const { os << wert() << "\n"; }
};
int main() {
    Basis ba{}; ba.print(std::cout);   // Basisaufruf
    Print pr{}; pr.print(std::cout);   // print überschrieben
    Wert we{}; we.print(std::cout);    // print aus Basis
    Beides be{}; be.print(std::cout);  // alles überschrieben
}

Godbolt Listing lst-0403-godb.cpp, https://godbolt.org/z/476G1xzKr:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/476G1xzKr 
#include <iostream>
struct Basis {
    int acht_ = 8;
    int wert() const { return acht_; }
    void print(std::ostream& os) const { os << wert() << "\n"; }
};
struct Print : public Basis {
    int neun_ = 9;
    void print(std::ostream& os) const { os << wert() << "\n"; }
};
struct Wert : public Basis {
    int zehn_ = 10;
    int wert() const { return zehn_; }
};
struct Beides : public Basis {
    int elf_ = 11;
    int wert() const { return elf_; }
    void print(std::ostream& os) const { os << wert() << "\n"; }
};
int main() {
    Basis ba{}; ba.print(std::cout);   // Basisaufruf
    Print pr{}; pr.print(std::cout);   // print überschrieben
    Wert we{}; we.print(std::cout);    // print aus Basis
    Beides be{}; be.print(std::cout);  // alles überschrieben
}

Listing 15.7: Mit »virtual« markierte Methoden werden zur Laufzeit aufgelöst.

Book listing lst-0404-book.cpp:

// https://godbolt.org/z/aj8cnox4f 
#include <iostream>

using std::ostream; using std::cout;
struct Basis2 {
    int acht_ = 8;
    virtual int wert() const          // virtuelle Methode
        { return acht_; }
    void print(ostream& os) const
        { os << wert() << "\n"; }
};
struct Wert2 : public Basis2 {
    int zehn_ = 10;
    virtual int wert() const override // überschreiben
        { return zehn_; }
};
int main() {
    Wert2 we2{}; we2.print(cout);     // verwenden
}

Godbolt Listing lst-0404-godb.cpp, https://godbolt.org/z/aj8cnox4f:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/aj8cnox4f 
#include <iostream>

using std::ostream; using std::cout;
struct Basis2 {
    int acht_ = 8;
    virtual int wert() const          // virtuelle Methode
        { return acht_; }
    void print(ostream& os) const
        { os << wert() << "\n"; }
};
struct Wert2 : public Basis2 {
    int zehn_ = 10;
    virtual int wert() const override // überschreiben
        { return zehn_; }
};
int main() {
    Wert2 we2{}; we2.print(cout);     // verwenden
}

Listing 15.8: Die abgeleitete Klasse erbt Methoden, aber nicht Konstruktoren der Elternklasse.

Book listing lst-0406-book.cpp:

// https://godbolt.org/z/57vexTPnn 
class Base {
public:
    Base() {}                 // null-Argument-Konstruktor
    explicit Base(int i) {}   // ein Argument
    Base(int i, int j) {}     // zwei Argumente
    void func() {};           // Methode
};

class Derived : public Base { // kein eigener Konstruktor
};

int main() {
    Base b0{};                // okay, null-Argument-Konstruktor
    Base b1{12};              // okay, ein Argument
    Base b2{6,18};            // okay, zwei Argumente
    Derived d0{};             // okay, Compiler generiert Defaultkonstruktor
    d0.func();                // okay, Methode wird geerbt
    Derived d1{7};            //                 (ERR)                 Fehler: kein Konstruktor für ein Argument
    Derived d2{3,13};         //                 (ERR)                 Fehler: kein Konstruktor für zwei Argumente
}

Godbolt Listing lst-0406-godb.cpp, https://godbolt.org/z/57vexTPnn:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/57vexTPnn 
class Base {
public:
    Base() {}                 // null-Argument-Konstruktor
    explicit Base(int i) {}   // ein Argument
    Base(int i, int j) {}     // zwei Argumente
    void func() {};           // Methode
};

class Derived : public Base { // kein eigener Konstruktor
};

int main() {
    Base b0{};                // okay, null-Argument-Konstruktor
    Base b1{12};              // okay, ein Argument
    Base b2{6,18};            // okay, zwei Argumente
    Derived d0{};             // okay, Compiler generiert Defaultkonstruktor
    d0.func();                // okay, Methode wird geerbt
    Derived d1{7};            //                 (ERR)                 Fehler: kein Konstruktor für ein Argument
    Derived d2{3,13};         //                 (ERR)                 Fehler: kein Konstruktor für zwei Argumente
}

Listing 15.9: Mit »using« importieren Sie alle Konstruktoren der Elternklasse.

Book listing lst-0407-book.cpp:

// https://godbolt.org/z/8b3Yvnjh4 
class Base {
public:
    Base() {}
    explicit Base(int i) {}
    Base(int i, int j) {}
    void func() {};           // Methode
};

class Derived : public Base {
public:
    using Base::Base;         // Importieren aller Konstruktoren der Elternklasse
};

int main() {
    Derived d0{};             // okay, importiert, nicht mehr generiert
    Derived d1{7};            // okay, wurde importiert
    Derived d2{3,13};         // okay, wurde importiert
}

Godbolt Listing lst-0407-godb.cpp, https://godbolt.org/z/8b3Yvnjh4:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8b3Yvnjh4 
class Base {
public:
    Base() {}
    explicit Base(int i) {}
    Base(int i, int j) {}
    void func() {};           // Methode
};

class Derived : public Base {
public:
    using Base::Base;         // Importieren aller Konstruktoren der Elternklasse
};

int main() {
    Derived d0{};             // okay, importiert, nicht mehr generiert
    Derived d1{7};            // okay, wurde importiert
    Derived d2{3,13};         // okay, wurde importiert
}

Listing 15.10: Die Übergabe als Wert kopiert nur den gemeinsamen Teil des Typs.

Book listing lst-0408-book.cpp:

// https://godbolt.org/z/jfocr7qf1 
//… Basis2 und Wert2 wie gehabt …
void ausgabe(Basis2 x) {        // Übergabe als Wert
    x.print(cout);
}
int main() {
    Basis2 ba2{}; ausgabe(ba2); // gibt 8 aus
    Wert2 we2{}; ausgabe(we2);  // gibt auch 8 aus
}

Godbolt Listing lst-0408-godb.cpp, https://godbolt.org/z/jfocr7qf1:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jfocr7qf1 
//… Basis2 und Wert2 wie gehabt …
void ausgabe(Basis2 x) {        // Übergabe als Wert
    x.print(cout);
}
int main() {
    Basis2 ba2{}; ausgabe(ba2); // gibt 8 aus
    Wert2 we2{}; ausgabe(we2);  // gibt auch 8 aus
}

Listing 15.11: Die abgeleitete Klasse als Argumenttyp zu einer Funktion erlaubt nicht den Aufruf mit einer Variable der Basisklasse als Wertparameter.

Book listing lst-0409-book.cpp:

// https://godbolt.org/z/j9Er3s1xo 
//… Basis2 und Wert2 wie gehabt …
void ausgabe(Wert2 x) {         // abgeleitete Klasse als Wert
    x.print(cout);
}
int main() {
    Basis2 ba2{}; ausgabe(ba2); //                 (ERR)  ba2 kann nicht in Wert2 umgewandelt werden
    Wert2 we2{}; ausgabe(we2);  // gibt 10 aus
}

Godbolt Listing lst-0409-godb.cpp, https://godbolt.org/z/j9Er3s1xo:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/j9Er3s1xo 
//… Basis2 und Wert2 wie gehabt …
void ausgabe(Wert2 x) {         // abgeleitete Klasse als Wert
    x.print(cout);
}
int main() {
    Basis2 ba2{}; ausgabe(ba2); //                 (ERR)  ba2 kann nicht in Wert2 umgewandelt werden
    Wert2 we2{}; ausgabe(we2);  // gibt 10 aus
}

Listing 15.12: Die Übergabe als Referenz verändert die Instanz nicht.

Book listing lst-0410-book.cpp:

// https://godbolt.org/z/3nvrvrrYW 
//… Basis2 und Wert2 wie gehabt …
void ausgabe(Basis2& x) {       // Übergabe als Referenz
    x.print(cout);
}

int main() {
    Basis2 ba2{}; ausgabe(ba2); // gibt 8 aus
    Wert2 we2{}; ausgabe(we2);  // gibt 10 aus, denn das Objekt wird nicht kopiert
}

Godbolt Listing lst-0410-godb.cpp, https://godbolt.org/z/3nvrvrrYW:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3nvrvrrYW 
//… Basis2 und Wert2 wie gehabt …
void ausgabe(Basis2& x) {       // Übergabe als Referenz
    x.print(cout);
}

int main() {
    Basis2 ba2{}; ausgabe(ba2); // gibt 8 aus
    Wert2 we2{}; ausgabe(we2);  // gibt 10 aus, denn das Objekt wird nicht kopiert
}

Listing 16.1: Welche Variablen können Sie bei »x1« bis »x5« einsetzen?

Book listing lst-0411-book.cpp:

// https://godbolt.org/z/K7TqWrjbo 
struct MeinWert { /* irgendwas */ };
MeinWert globalWert{};                    // globale Klasseninstanz

void funktion(const MeinWert &paramRef) {
    if( /*...*/ ) funktion( /*x1?*/ );        // irgendeine Funktion aufrufen
    MeinWert lokalWert{};                 // lokale Klasseninstanz
}                                         // Ende der Funktion

int main() {
    MeinWert mwert1{};
    funktion( /*x2?*/ );
    funktion( MeinWert{} );               // temporärer Wert
    {
        MeinWert mwert2{};
        funktion( /*x3?*/ );
        MeinWert mwert3{};
    }                                     // Ende des inneren Blocks
    funktion( /*x4?*/ );
    MeinWert mwert4{};
    funktion( /*x5?*/ );
}                                         // Ende der main-Funktion

Godbolt Listing lst-0411-godb.cpp, https://godbolt.org/z/K7TqWrjbo:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/K7TqWrjbo 
struct MeinWert { /* irgendwas */ };
MeinWert globalWert{};                    // globale Klasseninstanz

void funktion(const MeinWert &paramRef) {
    if( /*...*/ ) funktion( /*x1?*/ );        // irgendeine Funktion aufrufen
    MeinWert lokalWert{};                 // lokale Klasseninstanz
}                                         // Ende der Funktion

int main() {
    MeinWert mwert1{};
    funktion( /*x2?*/ );
    funktion( MeinWert{} );               // temporärer Wert
    {
        MeinWert mwert2{};
        funktion( /*x3?*/ );
        MeinWert mwert3{};
    }                                     // Ende des inneren Blocks
    funktion( /*x4?*/ );
    MeinWert mwert4{};
    funktion( /*x5?*/ );
}                                         // Ende der main-Funktion

Listing 16.2: Wenn Sie eine Funktion mit einem Parameter aufrufen, für den der Compiler zur Umwandlung einen Konstruktor aufruft, erzeugt er einen Tempwert.

Book listing lst-0412-book.cpp:

// https://godbolt.org/z/TvKP7Ghvh 
#include <string>
#include <iostream>                      // cout
using std::string; using std::cout;

struct Value {
    int wert_;
    Value(int wert)                      // 1-Arg-Konstruktor = Typumwandlung
        : wert_{wert} {}
};

size_t laenge(string arg) {
    return arg.size();
}
Value doppel(Value v) {
    return Value{ v.wert_*2 };
}
int main() {
    cout << laenge("Hipphopp") << "\n";  // const char* in string
    cout << doppel(10).wert_ << "\n";    // int in Value
    string name {"Gandalf"};
    cout << ( name + " der Graue" ) << "\n"; // string + const char*
}

Godbolt Listing lst-0412-godb.cpp, https://godbolt.org/z/TvKP7Ghvh:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TvKP7Ghvh 
#include <string>
#include <iostream>                      // cout
using std::string; using std::cout;

struct Value {
    int wert_;
    Value(int wert)                      // 1-Arg-Konstruktor = Typumwandlung
        : wert_{wert} {}
};

size_t laenge(string arg) {
    return arg.size();
}
Value doppel(Value v) {
    return Value{ v.wert_*2 };
}
int main() {
    cout << laenge("Hipphopp") << "\n";  // const char* in string
    cout << doppel(10).wert_ << "\n";    // int in Value
    string name {"Gandalf"};
    cout << ( name + " der Graue" ) << "\n"; // string + const char*
}

Listing 16.3: Ein Destruktor wird beim Entfernen eines Objekts ausgeführt.

Book listing lst-0413-book.cpp:

// https://godbolt.org/z/qzbnK9v1o 
#include <string>
#include <iostream>
#include <iomanip>   // setw
using std::cout; using std::setw; using std::string;
struct MeinWert {
    static int zaehler;              // static: existiert nur einmal für alle Instanzen
    int nummer_;                     // Einrücktiefe dieser Instanz für die Ausgabe
    string name_;                    // Name dieser Instanz für die Ausgabe
    explicit MeinWert(string name)
        : nummer_{++zaehler}         // Zähler für Einrücktiefe pro Instanz hochzählen
        , name_{name}               // Name des Objekts für Ausgabe merken
    {
        cout << setw(nummer_) << " " // nummer_ verwenden für Einrücktiefe
             << "Konstruktor " << name_ << "\n"; // Instanzname ausgeben        }
    ~MeinWert() {                    // Destruktor
        cout << setw(nummer_) << " " << "Destruktor " << name_ << "\n";
    }
};
int MeinWert::zaehler = 0;           // Initialisierung der statischen Klassenvariablen

Godbolt Listing lst-0413-godb.cpp, https://godbolt.org/z/qzbnK9v1o:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qzbnK9v1o 
#include <string>
#include <iostream>
#include <iomanip>   // setw
using std::cout; using std::setw; using std::string;
struct MeinWert {
    static int zaehler;              // static: existiert nur einmal für alle Instanzen
    int nummer_;                     // Einrücktiefe dieser Instanz für die Ausgabe
    string name_;                    // Name dieser Instanz für die Ausgabe
    explicit MeinWert(string name)
        : nummer_{++zaehler}         // Zähler für Einrücktiefe pro Instanz hochzählen
        , name_{name}               // Name des Objekts für Ausgabe merken
    {
        cout << setw(nummer_) << " " // nummer_ verwenden für Einrücktiefe
             << "Konstruktor " << name_ << "\n"; // Instanzname ausgeben        }
    ~MeinWert() {                    // Destruktor
        cout << setw(nummer_) << " " << "Destruktor " << name_ << "\n";
    }
};
int MeinWert::zaehler = 0;           // Initialisierung der statischen Klassenvariablen

Listing 16.4: Hier werden viele Objekte erzeugt und zerstört.

Book listing lst-0414-book.cpp:

// https://godbolt.org/z/oY953arPj 
void funktion(const MeinWert &paramRef) {
    MeinWert lokalWert{"lokal"};
}

int main() {
    MeinWert mwert1{"mwert1"};
    funktion( MeinWert{"temp"} );
    funktion( mwert1 );
    {
        MeinWert mwert2{"mwert2"};
    }
}

Godbolt Listing lst-0414-godb.cpp, https://godbolt.org/z/oY953arPj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oY953arPj 
void funktion(const MeinWert &paramRef) {
    MeinWert lokalWert{"lokal"};
}

int main() {
    MeinWert mwert1{"mwert1"};
    funktion( MeinWert{"temp"} );
    funktion( mwert1 );
    {
        MeinWert mwert2{"mwert2"};
    }
}

Listing 16.5: Diese Ausgabe zeigt, wann Objekte erzeugt und zerstört werden.

Book listing lst-0415-book.cpp:

Konstruktor mwert1
 Konstruktor temp
  Konstruktor lokal
  Destruktor lokal
 Destruktor temp
   Konstruktor lokal
   Destruktor lokal
    Konstruktor mwert2
    Destruktor mwert2
Destruktor mwert1

Listing 16.6: Ein einfaches Beispiel für eine C-Schnittstelle zu einer Ressource

Book listing lst-0416-book.cpp:

// https://godbolt.org/z/54dzsb31z 
#ifndef DATABASE_HPP
#define DATABASE_HPP

typedef void* db_handle_t;

db_handle_t db_open(const char* filename);
void db_close(db_handle_t db);
int db_execute(db_handle_t db, const char* query);

#endif

Godbolt Listing lst-0416-godb.cpp, https://godbolt.org/z/54dzsb31z:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/54dzsb31z 
#ifndef DATABASE_HPP
#define DATABASE_HPP

typedef void* db_handle_t;

db_handle_t db_open(const char* filename);
void db_close(db_handle_t db);
int db_execute(db_handle_t db, const char* query);

#endif

Listing 16.7: Wenn Sie eine Ressource schließen müssen, dann eignet sich dafür der Destruktor.

Book listing lst-0417-book.cpp:

// https://godbolt.org/z/93PT8W9hY 
#include <iostream>              // cout
#include "database.hpp"          // Einbinden der fremden Programmierschnittstelle
class Database {
    db_handle_t db_;             // eingepackte Ressource
public:
    Database(const char* filename);
    ~Database();
    int execute(const char* query);
};
Database::Database(const char* filename)
    : db_{db_open(filename)}     // Anfordern der Ressource
    { }
Database::~Database() {
    db_close(db_);               // Freigeben der Ressource
}
int Database::execute(const char* query) {
    return db_execute(db_, query); // Nutzen der Ressource
}
int main() {
    Database db{ "kunden.dat" };   // Erzeugen des Wrappers
    std::cout << "Anzahl: "<< db.execute("select * from kunden") << "\n";
}                                  // automatisches Entfernen des Wrappers

Godbolt Listing lst-0417-godb.cpp, https://godbolt.org/z/93PT8W9hY:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/93PT8W9hY 
#include <iostream>              // cout
#include "database.hpp"          // Einbinden der fremden Programmierschnittstelle
class Database {
    db_handle_t db_;             // eingepackte Ressource
public:
    Database(const char* filename);
    ~Database();
    int execute(const char* query);
};
Database::Database(const char* filename)
    : db_{db_open(filename)}     // Anfordern der Ressource
    { }
Database::~Database() {
    db_close(db_);               // Freigeben der Ressource
}
int Database::execute(const char* query) {
    return db_execute(db_, query); // Nutzen der Ressource
}
int main() {
    Database db{ "kunden.dat" };   // Erzeugen des Wrappers
    std::cout << "Anzahl: "<< db.execute("select * from kunden") << "\n";
}                                  // automatisches Entfernen des Wrappers

Listing 16.8: Der Konstruktor initialisiert oder löst eine Exception aus.

Book listing lst-0418-book.cpp:

Database::Database(const char* filename)
    : db_{ db_open(filename) }
    {
        if(nullptr == db_) { // Fehler beim Öffnen
            throw IllegalArgumentException("Fehler beim Oeffnen der DB");
        }
    }

Listing 16.9: Beispiele für Yoda-Bedingungen mit »==«

Book listing lst-0420-book.cpp:

if("Yoda" == character) 
if(42 == antwort) 

Listing 16.10: Eine Yoda-Bedingung mit einem Methodenaufruf

Book listing lst-0421-book.cpp:

// https://godbolt.org/z/c3695v4r8 
#include "mein_string.hpp"
static const mein_string ZEBRA { "zebra" };
int main() {
    mein_string tier{ "pferd" };
    if(ZEBRA.equals(tier)) return 0;
    else return 1;
}

Godbolt Listing lst-0421-godb.cpp, https://godbolt.org/z/c3695v4r8:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/c3695v4r8 
#include "mein_string.hpp"
static const mein_string ZEBRA { "zebra" };
int main() {
    mein_string tier{ "pferd" };
    if(ZEBRA.equals(tier)) return 0;
    else return 1;
}

Listing 16.11: Der Konstruktor von »KannWerfen« kann mit einer Exception beendet werden.

Book listing lst-0422-book.cpp:

// https://godbolt.org/z/vaP4bdvns 
#include <iostream> // cout
#include <stdexcept> // runtime_error
struct KannWerfen {
    KannWerfen(int wasSollPassieren) {
        std::cout << "Konstruktor " << wasSollPassieren << "...\n";
        if(wasSollPassieren == 666)
            throw std::runtime_error("Testfehler");
        std::cout << "...Konstruktor fertig\n";
    }
    ~KannWerfen() {
        std::cout << "Destruktor.\n";
    }
};
int main() {
    try {
        KannWerfen kw1{0};               // okay, löst keine Ausnahme aus
    } catch(std::runtime_error &exc) {
        std::cout << "Gefangen-1: " << exc.what() << "\n";
    }
    try {
        KannWerfen kw2{666};             // löst aus, kw2 wird nicht erzeugt
    } catch(std::runtime_error &exc) {
        std::cout << "Gefangen-2: " << exc.what() << "\n";
    }
}

Godbolt Listing lst-0422-godb.cpp, https://godbolt.org/z/vaP4bdvns:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vaP4bdvns 
#include <iostream> // cout
#include <stdexcept> // runtime_error
struct KannWerfen {
    KannWerfen(int wasSollPassieren) {
        std::cout << "Konstruktor " << wasSollPassieren << "...\n";
        if(wasSollPassieren == 666)
            throw std::runtime_error("Testfehler");
        std::cout << "...Konstruktor fertig\n";
    }
    ~KannWerfen() {
        std::cout << "Destruktor.\n";
    }
};
int main() {
    try {
        KannWerfen kw1{0};               // okay, löst keine Ausnahme aus
    } catch(std::runtime_error &exc) {
        std::cout << "Gefangen-1: " << exc.what() << "\n";
    }
    try {
        KannWerfen kw2{666};             // löst aus, kw2 wird nicht erzeugt
    } catch(std::runtime_error &exc) {
        std::cout << "Gefangen-2: " << exc.what() << "\n";
    }
}

Listing 16.12: Teilweise initialisierte Datenfelder werden auch bei einer Exception weggeräumt.

Book listing lst-0423-book.cpp:

class Mega {
    std::vector<int>     data_;
    KannWerfen           kannWerfen_;
    std::map<string,int> mehr_;
public:
    Mega()
      : data_{}
      , kannWerfen_{666}  // löst eine Exception aus
      , mehr_{}
      { }
};

Listing 16.13: Die Übergabe als Wert erstellt Objekte mit dem vom Compiler erzeugten Kopierkonstruktor.

Book listing lst-0424-book.cpp:

// https://godbolt.org/z/KGEe7hj1b 
void funktion(MeinWert paramWert) {
    std::cout << "(funktion)\n";
    MeinWert lokalWert{"lokal"};
}
int main() {
    MeinWert mwert1{"mwert1"};
    funktion( MeinWert{"temp"} );
    funktion( mwert1 );
    {
        MeinWert mwert2{"mwert2"};
    }
}

Godbolt Listing lst-0424-godb.cpp, https://godbolt.org/z/KGEe7hj1b:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KGEe7hj1b 
void funktion(MeinWert paramWert) {
    std::cout << "(funktion)\n";
    MeinWert lokalWert{"lokal"};
}
int main() {
    MeinWert mwert1{"mwert1"};
    funktion( MeinWert{"temp"} );
    funktion( mwert1 );
    {
        MeinWert mwert2{"mwert2"};
    }
}

Listing 16.14: Der Kopierkonstruktor bekommt eine konstante Referenz der Klasse als Argument.

Book listing lst-0425-book.cpp:

// https://godbolt.org/z/j67W4zPWE 
struct MeinWert {
   static int zaehler;
   int nummer_;
   string name_;
   explicit MeinWert(string name) // wie zuvor
      : nummer_{++zaehler} , name_{name}
      { cout << setw(nummer_) << '_'  << "Konstruktor " << name_ << "\n"; }
   MeinWert(const MeinWert &orig) // neuer Kopierkonstruktor
      : nummer_{++zaehler} , name_{orig.name_ + "-Kopie"}
      { cout << setw(nummer_)<<" " << "Kopierkonstruktor " << name_ << "\n"; }
   ~MeinWert() { // wie zuvor
      cout << setw(nummer_)<<" " << "Destruktor " << name_ << "\n";
   }
};
int MeinWert::zaehler = 0;

Godbolt Listing lst-0425-godb.cpp, https://godbolt.org/z/j67W4zPWE:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/j67W4zPWE 
struct MeinWert {
   static int zaehler;
   int nummer_;
   string name_;
   explicit MeinWert(string name) // wie zuvor
      : nummer_{++zaehler} , name_{name}
      { cout << setw(nummer_) << '_'  << "Konstruktor " << name_ << "\n"; }
   MeinWert(const MeinWert &orig) // neuer Kopierkonstruktor
      : nummer_{++zaehler} , name_{orig.name_ + "-Kopie"}
      { cout << setw(nummer_)<<" " << "Kopierkonstruktor " << name_ << "\n"; }
   ~MeinWert() { // wie zuvor
      cout << setw(nummer_)<<" " << "Destruktor " << name_ << "\n";
   }
};
int MeinWert::zaehler = 0;

Listing 16.15: Kopie und Zuweisung

Book listing lst-0426-book.cpp:

void byVal(MeinWert arg) { }
int main() {
    MeinWert wert1{"ABCD"}; // neue Instanz, konstruiert per string
    MeinWert wert2{wert1};  // neue Instanz, konstruiert per Kopie
    MeinWert wert3 = wert1; // neue Instanz, ebenfalls per Kopie, trotz =
    byVal(wert1);           // eine neue Instanz per Kopie
    wert1 = wert2;          // keine neue Instanz, sondern eine Zuweisung
}

Listing 16.16: Das Schema für die Implementierung eines eigenen Zuweisungsoperators

Book listing lst-0429-book.cpp:

struct MeinWert {
    // … alles andere wie bisher
    MeinWert& operator=(const MeinWert& rechts) {
        if(this != &rechts) { // 1. auf Selbstzuweisung prüfen
            // 2. Freigeben bisheriger Ressourcen; hier keine
            // 3. elementweises Übertragen durch Zuweisung oder Ähnliches
            name_ = rechts.name_ + "-Zuweisung (zuvor " + name_ + ")";
            /* nummer_ bleibt, und damit die originale Einrückung */
        }
        return *this; // 4. sich selbst zurückgeben
    }
};

Listing 16.17: »const«-Datenelement zunächst ohne Zuweisungsoperator

Book listing lst-0430-book.cpp:

struct MeineNummer {

    const int nummer_;         // konstantes Datenfeld

    explicit MeineNummer(int v)
        : nummer_{v}           // Initialisierung des konstanten Datenfelds
        {}
};

int main() {
    MeineNummer c1{4};
    MeineNummer c2{7};
    c1 = c2;                   //             (ERR)  Fehler: Zuweisung vom Compiler gestrichen
}

Listing 16.18: Mit »= delete« entfernen Sie Operationen manuell.

Book listing lst-0431-book.cpp:

// https://godbolt.org/z/acWjozE15 
struct MeineNummer {
    int nummer_; // variables Datenfeld

    explicit MeineNummer(int v)
        : nummer_{v} {}
    MeineNummer& operator=(const MeineNummer&) = delete; // Zuweisung streichen
    MeineNummer(const MeineNummer&) = delete;            // Kopie streichen
};
int main() {
    MeineNummer c1{4};
    MeineNummer c2{7};
    c1 = c2;            //             (ERR)  Fehler – Zuweisung vom Programmierer gestrichen
    MeineNummer c3{c1}; //             (ERR)  Fehler – Kopie vom Programmierer gestrichen
}

Godbolt Listing lst-0431-godb.cpp, https://godbolt.org/z/acWjozE15:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/acWjozE15 
struct MeineNummer {
    int nummer_; // variables Datenfeld

    explicit MeineNummer(int v)
        : nummer_{v} {}
    MeineNummer& operator=(const MeineNummer&) = delete; // Zuweisung streichen
    MeineNummer(const MeineNummer&) = delete;            // Kopie streichen
};
int main() {
    MeineNummer c1{4};
    MeineNummer c2{7};
    c1 = c2;            //             (ERR)  Fehler – Zuweisung vom Programmierer gestrichen
    MeineNummer c3{c1}; //             (ERR)  Fehler – Kopie vom Programmierer gestrichen
}

Listing 16.19: Mit den gelöschten Funktionen verhindert der Compiler eine fehlerhafte Benutzung der Klasse.

Book listing lst-0432-book.cpp:

// https://godbolt.org/z/PfW8oKPK4 
#include <iostream>              // cout
#include "database.hpp"          // Einbinden der fremden Programmierschnittstelle

class Database {
    const db_handle_t db_;                         // konstant machen
public:
    Database(const char* filename);
    ~Database();
    int execute(const char* query);
    Database(const Database&) = delete;            // Kopieren verbieten
    Database& operator=(const Database&) = delete; // Zuweisung verbieten
};
// … Implementierungen wie gehabt …
int main() {
    Database db{ "kunden.dat" };
    std::cout << "Anzahl: "<< db.execute("select * from kunden") << "\n";
    Database db2{ db }; //                 (ERR)               Compiler verhindert gefährliche Kopie
    db = db2;           //                 (ERR)               Compiler verhindert gefährliche Zuweisung
}

Godbolt Listing lst-0432-godb.cpp, https://godbolt.org/z/PfW8oKPK4:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/PfW8oKPK4 
#include <iostream>              // cout
#include "database.hpp"          // Einbinden der fremden Programmierschnittstelle

class Database {
    const db_handle_t db_;                         // konstant machen
public:
    Database(const char* filename);
    ~Database();
    int execute(const char* query);
    Database(const Database&) = delete;            // Kopieren verbieten
    Database& operator=(const Database&) = delete; // Zuweisung verbieten
};
// … Implementierungen wie gehabt …
int main() {
    Database db{ "kunden.dat" };
    std::cout << "Anzahl: "<< db.execute("select * from kunden") << "\n";
    Database db2{ db }; //                 (ERR)               Compiler verhindert gefährliche Kopie
    db = db2;           //                 (ERR)               Compiler verhindert gefährliche Zuweisung
}

Listing 16.20: Die Klasse enthält wahrscheinlich große Datenmengen, die teuer zu kopieren sind. Doch was wird hier kopiert?

Book listing lst-0433-book.cpp:

// https://godbolt.org/z/MT3MPs3rE 
#include <vector>
class Image {
    std::vector<std::byte> data_;
public:
    explicit Image(const char *fn) { /*...*/ }
    // Compiler generiert (u. a.): 
    // Kopierkonstruktor, Zuweisung, aber auch Verschiebungen
};
std::vector<Image> loadCollection(bool empty) {
    if(empty) return std::vector<Image>{};
    std::vector<Image> result {};                // für Rückgabe; zunächst leer
    // drei Bilder in die Sammlung … kopieren?
    result.push_back( Image{"MonaLisa.png"} );
    result.push_back( Image{"DerSchrei.png"} );
    result.push_back( Image{"JungeMitPfeife.png"} );
    return result; // Sammlung als Wert zurückgeben
}
int main() {
    // Rückgabe in Variable speichern
    std::vector<Image> sammlung = loadCollection(false);
}

Godbolt Listing lst-0433-godb.cpp, https://godbolt.org/z/MT3MPs3rE:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MT3MPs3rE 
#include <vector>
class Image {
    std::vector<std::byte> data_;
public:
    explicit Image(const char *fn) { /*...*/ }
    // Compiler generiert (u. a.): 
    // Kopierkonstruktor, Zuweisung, aber auch Verschiebungen
};
std::vector<Image> loadCollection(bool empty) {
    if(empty) return std::vector<Image>{};
    std::vector<Image> result {};                // für Rückgabe; zunächst leer
    // drei Bilder in die Sammlung … kopieren?
    result.push_back( Image{"MonaLisa.png"} );
    result.push_back( Image{"DerSchrei.png"} );
    result.push_back( Image{"JungeMitPfeife.png"} );
    return result; // Sammlung als Wert zurückgeben
}
int main() {
    // Rückgabe in Variable speichern
    std::vector<Image> sammlung = loadCollection(false);
}

Listing 16.21: Implementierung der beiden Verschiebeoperationen

Book listing lst-0434-book.cpp:

// https://godbolt.org/z/6xjeYWe7c 
#include <vector>
class Image {
    std::vector<std::byte> data_;              // byte gibt es seit C++17
public:
    explicit Image(const char *fn) { /*...*/ }
    Image(Image&& other) noexcept              // Verschiebekonstruktor
        : data_{} // leer erzeugen
    {
        using std::swap;
        swap(data_, other.data_);
    }
    Image& operator=(Image&& other) noexcept { // Verschiebeoperator
        using std::swap;
        swap(data_, other.data_);
        return *this;
    }
};

Godbolt Listing lst-0434-godb.cpp, https://godbolt.org/z/6xjeYWe7c:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6xjeYWe7c 
#include <vector>
class Image {
    std::vector<std::byte> data_;              // byte gibt es seit C++17
public:
    explicit Image(const char *fn) { /*...*/ }
    Image(Image&& other) noexcept              // Verschiebekonstruktor
        : data_{} // leer erzeugen
    {
        using std::swap;
        swap(data_, other.data_);
    }
    Image& operator=(Image&& other) noexcept { // Verschiebeoperator
        using std::swap;
        swap(data_, other.data_);
        return *this;
    }
};

Listing 16.22: Infix-, Funktions- und Methodenschreibweise für Operatoren

Book listing lst-0440-book.cpp:

// https://godbolt.org/z/fefP5d343 
#include <iostream>
using std::cout; using std::ostream;
struct Widget {
    bool operator<(const Widget&) const {      // Methodenschreibweise
        return true;                           // immer true
    }
};
bool operator<(const Widget&, const Widget&) { // Funktionsschreibweise
    return false;                              // immer false
}
int main() {
    Widget x{};
    Widget y{};
    cout << (operator<(x, y)      // ruft Funktionsschreibweise auf
        ? "Methode1\n" : "Funktion1\n");
    cout << (y.operator<(x)       // ruft Methodenschreibweise auf
        ? "Methode2\n" : "Funktion2\n");
    cout << (x < y                // Infix-Schreibweise, lässt die Wahl, hier Methode
        ? "Methode3\n" : "Funktion3\n");
}

Godbolt Listing lst-0440-godb.cpp, https://godbolt.org/z/fefP5d343:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fefP5d343 
#include <iostream>
using std::cout; using std::ostream;
struct Widget {
    bool operator<(const Widget&) const {      // Methodenschreibweise
        return true;                           // immer true
    }
};
bool operator<(const Widget&, const Widget&) { // Funktionsschreibweise
    return false;                              // immer false
}
int main() {
    Widget x{};
    Widget y{};
    cout << (operator<(x, y)      // ruft Funktionsschreibweise auf
        ? "Methode1\n" : "Funktion1\n");
    cout << (y.operator<(x)       // ruft Methodenschreibweise auf
        ? "Methode2\n" : "Funktion2\n");
    cout << (x < y                // Infix-Schreibweise, lässt die Wahl, hier Methode
        ? "Methode3\n" : "Funktion3\n");
}

Listing 16.23: Eine »friend«-Funktion ist keine Methode, auch wenn sie innerhalb der Klasse steht oder dort definiert ist.

Book listing lst-0441-book.cpp:

// https://godbolt.org/z/Wvr3aK75G 
#include <compare>              // für <=>
class Value {
    // Wenn Sie class verwenden, geht es mit Privatem los.
    int value_; 
public:
    explicit Value(int value) : value_{value} {}

    // freie Funktionen, aber als friend deklariert
    friend Value operator+(const Value& li, const Value& re);
    friend Value operator-(const Value& li, const Value& re)
        { return Value{li.value_ - re.value_};  // innerhalb auch definiert
    }
    // operator<=> braucht nicht friend zu sein.
    // für alle Vergleiche: <, >, <=, >= sowie == und !=
    auto operator<=>(const Value& re) const = default; 
};

// Definition der zuvor deklarierten friend-Funktion:
Value operator+(const Value& li, const Value& re) {
    return Value{li.value_ + re.value_}; // Zugriff auf Privates erlaubt
}

int main() {
    Value sieben{7}; Value drei{3}; Value zwei{2};
    if((drei+zwei) < sieben) {    // operator+, dann operarator< via <=>
        return 0;                 // okay
    } else {
        return 1;                 // etwas ist falsch gelaufen
    }
}

Godbolt Listing lst-0441-godb.cpp, https://godbolt.org/z/Wvr3aK75G:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Wvr3aK75G 
#include <compare>              // für <=>
class Value {
    // Wenn Sie class verwenden, geht es mit Privatem los.
    int value_; 
public:
    explicit Value(int value) : value_{value} {}

    // freie Funktionen, aber als friend deklariert
    friend Value operator+(const Value& li, const Value& re);
    friend Value operator-(const Value& li, const Value& re)
        { return Value{li.value_ - re.value_};  // innerhalb auch definiert
    }
    // operator<=> braucht nicht friend zu sein.
    // für alle Vergleiche: <, >, <=, >= sowie == und !=
    auto operator<=>(const Value& re) const = default; 
};

// Definition der zuvor deklarierten friend-Funktion:
Value operator+(const Value& li, const Value& re) {
    return Value{li.value_ + re.value_}; // Zugriff auf Privates erlaubt
}

int main() {
    Value sieben{7}; Value drei{3}; Value zwei{2};
    if((drei+zwei) < sieben) {    // operator+, dann operarator< via <=>
        return 0;                 // okay
    } else {
        return 1;                 // etwas ist falsch gelaufen
    }
}

Listing 16.24: Ein beinahe mit allen Operatoren voll ausgerüsteter Datentyp

Book listing lst-0442-book.cpp:

// https://godbolt.org/z/Gf38nTa1q 
#include <iostream>  // istream, ostream, cout
class Num {
  int val_ = 0;
public:
  int& operator*();  // Dereferenzieren: Zugriff auf den Wert direkt erhalten
  const int& operator*() const; // Dereferenzieren: Lesezugriff auf den Wert
  Num() {}
  explicit Num(int value) : val_{value} {}
  // einstellige Operatoren
  Num& operator++(); // Pre-Inkrement
  Num& operator--(); // Pre-Dekrement
  Num operator+();   // Positiv
  Num operator-();   // Negieren
  Num operator~();   // bitweises Invertieren
  // zweistellige Operatoren
  // - zusammengesetzte Zuweisungen, arithmetisch
  Num& operator+=(const Num& re) { val_ += *re; return *this; }
  Num& operator-=(const Num& re) { val_ -= *re; return *this; }
  Num& operator*=(const Num& re) { val_ *= *re; return *this; }
  Num& operator/=(const Num& re) { val_ /= *re; return *this; }
  Num& operator%=(const Num& re) { val_ %= *re; return *this; }
  // - zusammengesetzte Zuweisungen, bitweise
  Num& operator|=(const Num& re) { val_ |= *re; return *this; }
  Num& operator&=(const Num& re) { val_ &= *re; return *this; }
  Num& operator^=(const Num& re) { val_ ^= *re; return *this; }
  Num& operator<<=(int n) { val_ <<= n; return *this; }
  Num& operator>>=(int n) { val_ >>= n; return *this; }
  // - Variation zusammengesetzter Zuweisungen, für einfachere Bedienung
  Num& operator+=(int re) { val_ += re; return *this; }
  Num& operator-=(int re) { val_ -= re; return *this; }
  // zweistellige Operatoren, mit Call-by-Value für den ersten Parameter
  // und die die zusammengesetzte Zuweisung zu Hilfe nehmen
  // - Arithmetik
  friend Num operator+(Num li, const Num& re) { return li += re; }
  friend Num operator-(Num li, const Num& re) { return li -= re; }
  friend Num operator*(Num li, const Num& re) { return li *= re; }
  friend Num operator/(Num li, const Num& re) { return li /= re; }
  friend Num operator%(Num li, const Num& re) { return li %= re; }
  // - bitweise
  friend Num operator|(Num li, const Num& re) { return li |= re; }
  friend Num operator&(Num li, const Num& re) { return li &= re; }
  friend Num operator^(Num li, const Num& re) { return li ^= re; }
  // - Vergleiche
  // - … fundamental für Standardcontainer und -algorithmen
  friend bool operator==(const Num& li, const Num& re) { return *li == *re; }
  auto operator<=>(const Num& re) const {return val_ <=> *re; } // C++20
  // - Ein- und Ausgabe
  friend std::ostream& operator<<(std::ostream& os, const Num& arg);
  friend std::istream& operator>>(std::istream& is,  Num& arg);
};
// einstellige Operatoren
Num& Num::operator++() { ++val_; return *this; }
Num& Num::operator--() { --val_; return *this; }
Num Num::operator+() { return Num{val_}; }
Num Num::operator-() { return Num{-val_}; }
Num Num::operator~() { return Num{~val_}; }
int& Num::operator*() { return val_; }
const int& Num::operator*() const { return val_; }
// Ein- und Ausgabe
std::ostream& operator<<(std::ostream&os, const Num& arg) { return os<<*arg; }
std::istream& operator>>(std::istream&is, Num& arg) { return is>>*arg; }

Godbolt Listing lst-0442-godb.cpp, https://godbolt.org/z/Gf38nTa1q:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Gf38nTa1q 
#include <iostream>  // istream, ostream, cout
class Num {
  int val_ = 0;
public:
  int& operator*();  // Dereferenzieren: Zugriff auf den Wert direkt erhalten
  const int& operator*() const; // Dereferenzieren: Lesezugriff auf den Wert
  Num() {}
  explicit Num(int value) : val_{value} {}
  // einstellige Operatoren
  Num& operator++(); // Pre-Inkrement
  Num& operator--(); // Pre-Dekrement
  Num operator+();   // Positiv
  Num operator-();   // Negieren
  Num operator~();   // bitweises Invertieren
  // zweistellige Operatoren
  // - zusammengesetzte Zuweisungen, arithmetisch
  Num& operator+=(const Num& re) { val_ += *re; return *this; }
  Num& operator-=(const Num& re) { val_ -= *re; return *this; }
  Num& operator*=(const Num& re) { val_ *= *re; return *this; }
  Num& operator/=(const Num& re) { val_ /= *re; return *this; }
  Num& operator%=(const Num& re) { val_ %= *re; return *this; }
  // - zusammengesetzte Zuweisungen, bitweise
  Num& operator|=(const Num& re) { val_ |= *re; return *this; }
  Num& operator&=(const Num& re) { val_ &= *re; return *this; }
  Num& operator^=(const Num& re) { val_ ^= *re; return *this; }
  Num& operator<<=(int n) { val_ <<= n; return *this; }
  Num& operator>>=(int n) { val_ >>= n; return *this; }
  // - Variation zusammengesetzter Zuweisungen, für einfachere Bedienung
  Num& operator+=(int re) { val_ += re; return *this; }
  Num& operator-=(int re) { val_ -= re; return *this; }
  // zweistellige Operatoren, mit Call-by-Value für den ersten Parameter
  // und die die zusammengesetzte Zuweisung zu Hilfe nehmen
  // - Arithmetik
  friend Num operator+(Num li, const Num& re) { return li += re; }
  friend Num operator-(Num li, const Num& re) { return li -= re; }
  friend Num operator*(Num li, const Num& re) { return li *= re; }
  friend Num operator/(Num li, const Num& re) { return li /= re; }
  friend Num operator%(Num li, const Num& re) { return li %= re; }
  // - bitweise
  friend Num operator|(Num li, const Num& re) { return li |= re; }
  friend Num operator&(Num li, const Num& re) { return li &= re; }
  friend Num operator^(Num li, const Num& re) { return li ^= re; }
  // - Vergleiche
  // - … fundamental für Standardcontainer und -algorithmen
  friend bool operator==(const Num& li, const Num& re) { return *li == *re; }
  auto operator<=>(const Num& re) const {return val_ <=> *re; } // C++20
  // - Ein- und Ausgabe
  friend std::ostream& operator<<(std::ostream& os, const Num& arg);
  friend std::istream& operator>>(std::istream& is,  Num& arg);
};
// einstellige Operatoren
Num& Num::operator++() { ++val_; return *this; }
Num& Num::operator--() { --val_; return *this; }
Num Num::operator+() { return Num{val_}; }
Num Num::operator-() { return Num{-val_}; }
Num Num::operator~() { return Num{~val_}; }
int& Num::operator*() { return val_; }
const int& Num::operator*() const { return val_; }
// Ein- und Ausgabe
std::ostream& operator<<(std::ostream&os, const Num& arg) { return os<<*arg; }
std::istream& operator>>(std::istream&is, Num& arg) { return is>>*arg; }

Listing 16.25: Sie verwenden den mit Operatoren ausgestatteten Datentyp wie gewohnt.

Book listing lst-0443-book.cpp:

// https://godbolt.org/z/asaYr3ox6 
#include <iostream>                      // cout
int main() {
    using std::cout;
    Num a{1};
    *a = 7;                              // operator* liefert auch int&
    a += Num{3};                         // Inkrement mit Num
    cout << ( ++( ++a ) ) << "\n";       // Ausgabe: 12
    a -= 2;                              // Variation mit int
    cout << --(--a) << "\n";             // Ausgabe: 8
    Num b{99};
    cout << (a<b ? "ja\n" : "xxx\n");    // Ausgabe: ja
    cout << (a>b ? "xxx\n" : "nein\n");  // Ausgabe: nein
    b /= Num{3};          // b: 33
    b %= Num{10};         // b: 3
    b <<= 4;              // b: 48
    b >>= 2;              // b: 12
    Num c = b / Num{3} + a * Num{2}; // c: 20
}

Godbolt Listing lst-0443-godb.cpp, https://godbolt.org/z/asaYr3ox6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/asaYr3ox6 
#include <iostream>                      // cout
int main() {
    using std::cout;
    Num a{1};
    *a = 7;                              // operator* liefert auch int&
    a += Num{3};                         // Inkrement mit Num
    cout << ( ++( ++a ) ) << "\n";       // Ausgabe: 12
    a -= 2;                              // Variation mit int
    cout << --(--a) << "\n";             // Ausgabe: 8
    Num b{99};
    cout << (a<b ? "ja\n" : "xxx\n");    // Ausgabe: ja
    cout << (a>b ? "xxx\n" : "nein\n");  // Ausgabe: nein
    b /= Num{3};          // b: 33
    b %= Num{10};         // b: 3
    b <<= 4;              // b: 48
    b >>= 2;              // b: 12
    Num c = b / Num{3} + a * Num{2}; // c: 20
}

Listing 16.26: Dieser Datentyp demonstriert die booleschen Operatoren.

Book listing lst-0444-book.cpp:

// https://godbolt.org/z/ojeh8Gzcx 
#include <iostream>               // istream, ostream, cout
class Bool {
    bool val_ = false;
    bool& operator*()             // dereferenzieren; veränderbar
        { return val_; };
    const bool& operator*() const // dereferenzieren; nur lesen
        { return val_; }
public:
    constexpr Bool() {}
    explicit constexpr Bool(bool value)
        : val_{value} {}
    // einstellige Operatoren
    Bool operator!() const        // Nicht-Operator
        { return Bool{!val_}; };
    // zweistellige Operatoren
    friend Bool operator&&(const Bool &re, const Bool &li)
        { return Bool{*re && *li}; }
    friend Bool operator||(const Bool &re, const Bool &li)
        { return Bool{*re || *li}; }
    // Ein- und Ausgabe
    friend std::ostream& operator<<(std::ostream& os, const Bool& arg);
    friend std::istream& operator>>(std::istream& is,  Bool& arg);
};
std::ostream& operator<<(std::ostream& os, const Bool& arg)
    { return os << *arg; }
std::istream& operator>>(std::istream& is, Bool& arg)
    { return is >> *arg; }
// Konstanten
static constexpr Bool False{false};
static constexpr Bool True{true};
int main() {
    Bool jein = True && ( Bool{false} || !Bool{} ); // verwendet &&, || und !
    std::cout << jein << "\n"; // Ausgabe: 1
}

Godbolt Listing lst-0444-godb.cpp, https://godbolt.org/z/ojeh8Gzcx:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ojeh8Gzcx 
#include <iostream>               // istream, ostream, cout
class Bool {
    bool val_ = false;
    bool& operator*()             // dereferenzieren; veränderbar
        { return val_; };
    const bool& operator*() const // dereferenzieren; nur lesen
        { return val_; }
public:
    constexpr Bool() {}
    explicit constexpr Bool(bool value)
        : val_{value} {}
    // einstellige Operatoren
    Bool operator!() const        // Nicht-Operator
        { return Bool{!val_}; };
    // zweistellige Operatoren
    friend Bool operator&&(const Bool &re, const Bool &li)
        { return Bool{*re && *li}; }
    friend Bool operator||(const Bool &re, const Bool &li)
        { return Bool{*re || *li}; }
    // Ein- und Ausgabe
    friend std::ostream& operator<<(std::ostream& os, const Bool& arg);
    friend std::istream& operator>>(std::istream& is,  Bool& arg);
};
std::ostream& operator<<(std::ostream& os, const Bool& arg)
    { return os << *arg; }
std::istream& operator>>(std::istream& is, Bool& arg)
    { return is >> *arg; }
// Konstanten
static constexpr Bool False{false};
static constexpr Bool True{true};
int main() {
    Bool jein = True && ( Bool{false} || !Bool{} ); // verwendet &&, || und !
    std::cout << jein << "\n"; // Ausgabe: 1
}

Listing 16.27: Die Vergleichskategorien enthalten Konstanten für die Rückgabe.

Book listing lst-0446-book.cpp:

// https://godbolt.org/z/KxWb4q8q9 
#include <compare>  // partial_ordering etc
#include <set>
#include <iostream>
using namespace std;
struct Bruch {
  int z, n;  // zaehler / nenner
  partial_ordering operator<=>(const Bruch& re) const {
    if(n==0 || re.n==0) return partial_ordering::unordered;
    return (double)z / n <=> (double)re.z / re.n;
  }
};
int main() {
  set<Bruch> brueche{ {1,2}, {2,4}, {1,3}, {2,3}, {1,4}, {2,5}, {3,8}, {99,0} };
  for(auto b : brueche)
    cout << b.z << "/" << b.n << " ";
  cout << "\n"; // Ausgabe: 1/4 1/3 3/8 2/5 1/2 2/3
}

Godbolt Listing lst-0446-godb.cpp, https://godbolt.org/z/KxWb4q8q9:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KxWb4q8q9 
#include <compare>  // partial_ordering etc
#include <set>
#include <iostream>
using namespace std;
struct Bruch {
  int z, n;  // zaehler / nenner
  partial_ordering operator<=>(const Bruch& re) const {
    if(n==0 || re.n==0) return partial_ordering::unordered;
    return (double)z / n <=> (double)re.z / re.n;
  }
};
int main() {
  set<Bruch> brueche{ {1,2}, {2,4}, {1,3}, {2,3}, {1,4}, {2,5}, {3,8}, {99,0} };
  for(auto b : brueche)
    cout << b.z << "/" << b.n << " ";
  cout << "\n"; // Ausgabe: 1/4 1/3 3/8 2/5 1/2 2/3
}

Listing 16.28: Die Rückgabe von <=> können Sie mit null vergleichen.

Book listing lst-0448-book.cpp:

auto operator<=>(const Adresse& re) const {
  array a{strasse, plz, ort};
  array b{re.strasse, re.plz, re.ort};
  return lexicographical_compare_three_way(begin(a), end(a), begin(b), end(b));
}

Listing 16.29: Eine virtuelle Methode, die = 0 ist, nennt man pur virtuell oder abstrakt.

Book listing lst-0449-book.cpp:

// https://godbolt.org/z/f458s99Ga 
#include <string>
#include <iostream>
using std::string; using std::ostream;
class Shape {
    string color_;
public:
    virtual double calcArea() const = 0; // pur virtuelle Methode
    string getColor() const { return color_; }
    void setColor(const string& color) { color_ = color; }
    virtual ~Shape() {}
};
class Square : public Shape {
    double len_;
public:
    explicit Square(double len) : len_{len} {}
    double calcArea() const override { return len_*len_; }
};
class Circle : public Shape {
    double rad_;
public:
    explicit Circle(double rad) : rad_{rad} {}
    double calcArea() const override { return 3.1415*rad_*rad_; }
};
struct Calculator {
    Shape& shape_;
    Calculator(Shape& shape) : shape_{shape} { }
    void run(ostream& os) const {
        os << "The area of the shape is " << shape_.calcArea() << "\n";
    }
};
int main() {
    Square quadrat {5.0};
    Calculator ti { quadrat };
    ti.run(std::cout); // Ausgabe: The area of the shape is 25
}

Godbolt Listing lst-0449-godb.cpp, https://godbolt.org/z/f458s99Ga:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/f458s99Ga 
#include <string>
#include <iostream>
using std::string; using std::ostream;
class Shape {
    string color_;
public:
    virtual double calcArea() const = 0; // pur virtuelle Methode
    string getColor() const { return color_; }
    void setColor(const string& color) { color_ = color; }
    virtual ~Shape() {}
};
class Square : public Shape {
    double len_;
public:
    explicit Square(double len) : len_{len} {}
    double calcArea() const override { return len_*len_; }
};
class Circle : public Shape {
    double rad_;
public:
    explicit Circle(double rad) : rad_{rad} {}
    double calcArea() const override { return 3.1415*rad_*rad_; }
};
struct Calculator {
    Shape& shape_;
    Calculator(Shape& shape) : shape_{shape} { }
    void run(ostream& os) const {
        os << "The area of the shape is " << shape_.calcArea() << "\n";
    }
};
int main() {
    Square quadrat {5.0};
    Calculator ti { quadrat };
    ti.run(std::cout); // Ausgabe: The area of the shape is 25
}

Listing 16.30: Mit einem »enum« definieren Sie einen Typ mit eigenem Wertebereich.

Book listing lst-0454-book.cpp:

// https://godbolt.org/z/xhd7s1YhE 
#include <string>
using std::string;
enum class Ampelfarbe {
    ROT, GELB, ROTGELB, GRUEN
};
struct Ampel {
    Ampelfarbe farbe_;
    Ampel(Ampelfarbe farbe, string name) : farbe_{farbe} {}
};

Ampel erzeugeAmpel(Ampelfarbe farbe, string ampelName) {
    return Ampel{farbe, ampelName};
}

int main() {
    Ampel ampel = erzeugeAmpel(Ampelfarbe::ROT, "AX-001");
}

Godbolt Listing lst-0454-godb.cpp, https://godbolt.org/z/xhd7s1YhE:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xhd7s1YhE 
#include <string>
using std::string;
enum class Ampelfarbe {
    ROT, GELB, ROTGELB, GRUEN
};
struct Ampel {
    Ampelfarbe farbe_;
    Ampel(Ampelfarbe farbe, string name) : farbe_{farbe} {}
};

Ampel erzeugeAmpel(Ampelfarbe farbe, string ampelName) {
    return Ampel{farbe, ampelName};
}

int main() {
    Ampel ampel = erzeugeAmpel(Ampelfarbe::ROT, "AX-001");
}

Listing 16.31: In einem »enum« können Sie auch die gewünschten Zahlenwerte angeben.

Book listing lst-0457-book.cpp:

// https://godbolt.org/z/esevnfEM3 
enum class Wochentag {
    MO=1, DI, MI, DO, FR, SA, SO         // DI wird 2, MI wird 3 etc.
};
enum class Level {
   TRACE=1, DEBUG, INFO=10, ERROR, FATAL // auch mit Lücken möglich
};
void log(Level level) {
   int intLevel = (int)level;            // explizit in einen int umwandeln
   if(intLevel > 10) { /* ... */ }
}

Godbolt Listing lst-0457-godb.cpp, https://godbolt.org/z/esevnfEM3:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/esevnfEM3 
enum class Wochentag {
    MO=1, DI, MI, DO, FR, SA, SO         // DI wird 2, MI wird 3 etc.
};
enum class Level {
   TRACE=1, DEBUG, INFO=10, ERROR, FATAL // auch mit Lücken möglich
};
void log(Level level) {
   int intLevel = (int)level;            // explizit in einen int umwandeln
   if(intLevel > 10) { /* ... */ }
}

Listing 17.1: Verbieten Sie mit »= delete« vier der großen Fünf.

Book listing lst-0458-book.cpp:

// https://godbolt.org/z/1Ke5W5Pj5 
struct Typ {
    char* data_;            // roher Zeiger kann für unklare Besitzverhältnisse sorgen
    Typ(int n) : data_(new char[n]) {}
    ~Typ() { delete[] data_; }           // den Destruktor benötigen Sie

    Typ(const Typ&) = delete;            // keine Kopie zulassen
    Typ& operator=(const Typ&) = delete; // keine Zuweisung bitte
    Typ(Typ&&) = delete;                 // kein Verschieben
    Typ& operator=(Typ&&) = delete;      // kein Verschiebeoperator
};

Godbolt Listing lst-0458-godb.cpp, https://godbolt.org/z/1Ke5W5Pj5:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1Ke5W5Pj5 
struct Typ {
    char* data_;            // roher Zeiger kann für unklare Besitzverhältnisse sorgen
    Typ(int n) : data_(new char[n]) {}
    ~Typ() { delete[] data_; }           // den Destruktor benötigen Sie

    Typ(const Typ&) = delete;            // keine Kopie zulassen
    Typ& operator=(const Typ&) = delete; // keine Zuweisung bitte
    Typ(Typ&&) = delete;                 // kein Verschieben
    Typ& operator=(Typ&&) = delete;      // kein Verschiebeoperator
};

Listing 17.2: Statt eines rohen Zeigers verwenden Sie ein Standardkonstrukt und definieren keine Operation der Großen Fünf.

Book listing lst-0459-book.cpp:

// https://godbolt.org/z/xMbG771En 
#include <vector>
#include <memory>           // unique_ptr, shared_ptr
struct Typ1 {               // automatische komplette Kopie der Ressource
    std::vector<char> data_;
    Typ1(int n) : data_(n) {}
};
struct Typ2 {               // Kopie untersagt, Verschieben möglich
    std::unique_ptr<int[]> data_;
    Typ2(int n) : data_(new int[n]) {}
};
struct Typ3 {               // Kopie erlaubt, Ressource wird dann sauber geteilt
    std::shared_ptr<Typ1> data_;
    Typ3(int n) : data_(std::make_shared<Typ1>(n)) {}
};

Godbolt Listing lst-0459-godb.cpp, https://godbolt.org/z/xMbG771En:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xMbG771En 
#include <vector>
#include <memory>           // unique_ptr, shared_ptr
struct Typ1 {               // automatische komplette Kopie der Ressource
    std::vector<char> data_;
    Typ1(int n) : data_(n) {}
};
struct Typ2 {               // Kopie untersagt, Verschieben möglich
    std::unique_ptr<int[]> data_;
    Typ2(int n) : data_(new int[n]) {}
};
struct Typ3 {               // Kopie erlaubt, Ressource wird dann sauber geteilt
    std::shared_ptr<Typ1> data_;
    Typ3(int n) : data_(std::make_shared<Typ1>(n)) {}
};

Listing 17.3: In einer Hierarchie mit virtuellen Methoden müssen Sie den Destruktor der Basisklasse definieren und virtuell markieren.

Book listing lst-0460-book.cpp:

// https://godbolt.org/z/1xcqon7dM 
struct Base {
    virtual ~Base() {}; // definieren Sie den Destruktor, machen Sie ihn virtual
    virtual void other();
};

struct Derived : public Base {
    void other() override;
};

int main() {
    Base *obj = new Derived{};
    /* ... mehr Programmzeilen hier ... */
    delete obj;     // klappt, weil Base::~Base virtual ist
}

Godbolt Listing lst-0460-godb.cpp, https://godbolt.org/z/1xcqon7dM:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1xcqon7dM 
struct Base {
    virtual ~Base() {}; // definieren Sie den Destruktor, machen Sie ihn virtual
    virtual void other();
};

struct Derived : public Base {
    void other() override;
};

int main() {
    Base *obj = new Derived{};
    /* ... mehr Programmzeilen hier ... */
    delete obj;     // klappt, weil Base::~Base virtual ist
}

Listing 17.4: shared_ptr ruft immer den richtigen Destruktor auf, virtuell oder nicht.

Book listing lst-0461-book.cpp:

int main() {
    shared_ptr<Base> obj{ new Derived{} };
    /* ... mehr Programmzeilen hier ... */
} // obj wird korrekt weggeräumt

Listing 17.5: Eine RAII-Zeichenpufferklasse

Book listing lst-0463-book.cpp:

// https://godbolt.org/z/9eeG575Wz 
struct Puffer {
  const char *data;
  explicit Puffer(unsigned sz): data(new char[sz]) {}
  ~Puffer() { delete[] data; }
  Puffer(const Puffer&) = delete;
  Puffer& operator=(const Puffer&) = delete;
};

Godbolt Listing lst-0463-godb.cpp, https://godbolt.org/z/9eeG575Wz:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9eeG575Wz 
struct Puffer {
  const char *data;
  explicit Puffer(unsigned sz): data(new char[sz]) {}
  ~Puffer() { delete[] data; }
  Puffer(const Puffer&) = delete;
  Puffer& operator=(const Puffer&) = delete;
};

Listing 17.6: Wirft »right« eine Exception, entsteht mit »left« ein Leck.

Book listing lst-0464-book.cpp:

// https://godbolt.org/z/TK3vTv1EM 
struct StereoImage {
  Image *left, *right;
  StereoImage()
  : left(new Image)
  , right(new Image) // Gefahr!
  { }
  ~StereoImage() {
      delete left;
      delete right;
  }
};

Godbolt Listing lst-0464-godb.cpp, https://godbolt.org/z/TK3vTv1EM:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TK3vTv1EM 
struct StereoImage {
  Image *left, *right;
  StereoImage()
  : left(new Image)
  , right(new Image) // Gefahr!
  { }
  ~StereoImage() {
      delete left;
      delete right;
  }
};

Listing 17.7: Korrektes RAII für »StereoImage«

Book listing lst-0465-book.cpp:

// https://godbolt.org/z/cs4eEEGrf 
#include <memory> // unique_ptr
struct Image {
    /* ... */
};
struct StereoImage {
  std::unique_ptr<Image> left, right;
  StereoImage()
  : left(new Image)
  , right(new Image)
  { }
};

Godbolt Listing lst-0465-godb.cpp, https://godbolt.org/z/cs4eEEGrf:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cs4eEEGrf 
#include <memory> // unique_ptr
struct Image {
    /* ... */
};
struct StereoImage {
  std::unique_ptr<Image> left, right;
  StereoImage()
  : left(new Image)
  , right(new Image)
  { }
};

Listing 17.8: C-API in C++-Code

Book listing lst-0466-book.cpp:

// https://godbolt.org/z/GK4W1nKd4 
#include <string>
#include <stdexcept>
#include <sqlite3.h>
using std::string; using std::runtime_error;

void dbExec(const string &dbname, const string &sql) {
  sqlite3 *db;
  int errCode = sqlite3_open(dbname.c_str(), &db);  // Acquire
  if(errCode) {
    throw runtime_error("Fehler beim Öffnen der DB.");
  }
  errCode = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, nullptr);
  if(errCode) {
    throw runtime_error("Fehler SQL-Exec.");        //                 (ERR)  Nicht gut!
  }
  errCode = sqlite3_close(db);                      // Release
}

Godbolt Listing lst-0466-godb.cpp, https://godbolt.org/z/GK4W1nKd4:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/GK4W1nKd4 
#include <string>
#include <stdexcept>
#include <sqlite3.h>
using std::string; using std::runtime_error;

void dbExec(const string &dbname, const string &sql) {
  sqlite3 *db;
  int errCode = sqlite3_open(dbname.c_str(), &db);  // Acquire
  if(errCode) {
    throw runtime_error("Fehler beim Öffnen der DB.");
  }
  errCode = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, nullptr);
  if(errCode) {
    throw runtime_error("Fehler SQL-Exec.");        //                 (ERR)  Nicht gut!
  }
  errCode = sqlite3_close(db);                      // Release
}

Listing 17.9: C-API mit einfachem RAII

Book listing lst-0467-book.cpp:

// https://godbolt.org/z/hqrPjGjnK 
#include <sqlite3.h>
class DbWrapper {
  sqlite3 *db_;
public:
  // acquire resource
  DbWrapper(const string& dbname)
    : db_{nullptr}
  {
    const int errCode = sqlite3_open(dbname.c_str(), &db_);
    if(errCode)
      throw runtime_error("Fehler beim Öffnen"); // verhindert sqlite3_close
  }

  // release resource
  ~DbWrapper() {
    sqlite3_close(db_);  // Release
  }
  // access Resource
  sqlite3* operator*() { return db_; }
  // Keine Kopie und Zuweisung
  DbWrapper(const DbWrapper&) = delete;
  DbWrapper& operator=(const DbWrapper&) = delete;
};
void dbExec(const string &dbname, const string &sql) {
  DbWrapper db { dbname };
  const int errCode = sqlite3_exec(*db, sql.c_str(), nullptr, 
    nullptr, nullptr);
  if(errCode)
    throw runtime_error("Fehler SQL-Exec."); // Jetzt geht es!
}

Godbolt Listing lst-0467-godb.cpp, https://godbolt.org/z/hqrPjGjnK:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hqrPjGjnK 
#include <sqlite3.h>
class DbWrapper {
  sqlite3 *db_;
public:
  // acquire resource
  DbWrapper(const string& dbname)
    : db_{nullptr}
  {
    const int errCode = sqlite3_open(dbname.c_str(), &db_);
    if(errCode)
      throw runtime_error("Fehler beim Öffnen"); // verhindert sqlite3_close
  }

  // release resource
  ~DbWrapper() {
    sqlite3_close(db_);  // Release
  }
  // access Resource
  sqlite3* operator*() { return db_; }
  // Keine Kopie und Zuweisung
  DbWrapper(const DbWrapper&) = delete;
  DbWrapper& operator=(const DbWrapper&) = delete;
};
void dbExec(const string &dbname, const string &sql) {
  DbWrapper db { dbname };
  const int errCode = sqlite3_exec(*db, sql.c_str(), nullptr, 
    nullptr, nullptr);
  if(errCode)
    throw runtime_error("Fehler SQL-Exec."); // Jetzt geht es!
}

Listing 17.10: C-API mit einfachem RAII, ohne throw

Book listing lst-0468-book.cpp:

// https://godbolt.org/z/5bW9Evorc 
#include <string>
#include <sqlite3.h>
class DbWrapper {
  sqlite3 *db_;
public:
  DbWrapper(const std::string& dbname)
    : db_{nullptr}
  {
    const int errCode = sqlite3_open(dbname.c_str(), &db_);
    if(errCode) db_ = nullptr;  // als 'nicht erfolgreich' markieren
  }
  explicit operator bool() const {
    return db_ != nullptr;      // Markierung auswerten
  }
  ~DbWrapper() {
    if(db_) sqlite3_close(db_);
  }
  // ... Rest wie zuvor ...
};
bool dbExec(const std::string &dbname, const std::string &sql) {
  DbWrapper db { dbname };
  if(db) {                 // prüfe auf erfolgreiche Initialisierung
    const int errCode = sqlite3_exec(*db,sql.c_str(),nullptr,nullptr,nullptr);
    if(errCode)
      return false; // immer noch korrektes RAII
  }
  return (bool)db;
}

Godbolt Listing lst-0468-godb.cpp, https://godbolt.org/z/5bW9Evorc:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5bW9Evorc 
#include <string>
#include <sqlite3.h>
class DbWrapper {
  sqlite3 *db_;
public:
  DbWrapper(const std::string& dbname)
    : db_{nullptr}
  {
    const int errCode = sqlite3_open(dbname.c_str(), &db_);
    if(errCode) db_ = nullptr;  // als 'nicht erfolgreich' markieren
  }
  explicit operator bool() const {
    return db_ != nullptr;      // Markierung auswerten
  }
  ~DbWrapper() {
    if(db_) sqlite3_close(db_);
  }
  // ... Rest wie zuvor ...
};
bool dbExec(const std::string &dbname, const std::string &sql) {
  DbWrapper db { dbname };
  if(db) {                 // prüfe auf erfolgreiche Initialisierung
    const int errCode = sqlite3_exec(*db,sql.c_str(),nullptr,nullptr,nullptr);
    if(errCode)
      return false; // immer noch korrektes RAII
  }
  return (bool)db;
}

Listing 17.11: Nothrow-new wirft kein »bad_alloc«, sondern liefert »nullptr« zurück.

Book listing lst-0469-book.cpp:

// https://godbolt.org/z/s8KoE4ETs 
#include <new> // nothrow
std::string *ps = new(std::nothrow) std::string{};
if(ps == nullptr) {
   std::cerr << "Die Speicheranforderung ging schief\n";
   return SOME_ERROR;
}

Godbolt Listing lst-0469-godb.cpp, https://godbolt.org/z/s8KoE4ETs:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/s8KoE4ETs 
#include <new> // nothrow
std::string *ps = new(std::nothrow) std::string{};
if(ps == nullptr) {
   std::cerr << "Die Speicheranforderung ging schief\n";
   return SOME_ERROR;
}

Listing 18.1: Mit friend können Sie einer anderen Klasse Zugriff auf Privates erlauben.

Book listing lst-0470-book.cpp:

// https://godbolt.org/z/WqfMGaP71 
#include <iostream>
class Schrauber;
class Ding {
    int value_; // privat
public:
    explicit Ding(int value) : value_{value} {}
    void inc() { ++value_; }
    std::ostream& print(std::ostream& os) const { return os<<value_; }
    friend class Schrauber;
};
class Schrauber {
    const Ding &ding_;
public:
    explicit Schrauber(const Ding &ding) : ding_{ding} {}
    auto dingWert() const {
        return ding_.value_;                   // Zugriff auf Privates aus Ding
    }
};
int main() {
    Ding ding{45};
    ding.print(std::cout) << '\n';             // Ausgabe: 45
    Schrauber schrauber{ding};
    ding.inc(); // internen Wert verändern
    std::cout << schrauber.dingWert() << '\n'; // Ausgabe: 46
}

Godbolt Listing lst-0470-godb.cpp, https://godbolt.org/z/WqfMGaP71:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WqfMGaP71 
#include <iostream>
class Schrauber;
class Ding {
    int value_; // privat
public:
    explicit Ding(int value) : value_{value} {}
    void inc() { ++value_; }
    std::ostream& print(std::ostream& os) const { return os<<value_; }
    friend class Schrauber;
};
class Schrauber {
    const Ding &ding_;
public:
    explicit Schrauber(const Ding &ding) : ding_{ding} {}
    auto dingWert() const {
        return ding_.value_;                   // Zugriff auf Privates aus Ding
    }
};
int main() {
    Ding ding{45};
    ding.print(std::cout) << '\n';             // Ausgabe: 45
    Schrauber schrauber{ding};
    ding.inc(); // internen Wert verändern
    std::cout << schrauber.dingWert() << '\n'; // Ausgabe: 46
}

Listing 18.2: Die Klasse Tree hat Zugriff auf Privates von Node.

Book listing lst-0471-book.cpp:

// https://godbolt.org/z/dTnxobz6v 
#include <memory> // unique_ptr
#include <string>
using std::unique_ptr; using std::cout;
template <typename K, typename D> class Tree; // Vorwärtsdeklaration
template <typename K, typename D>
class Node {
    friend class Tree<K,D>; // Zugriff auf Privates erlauben
    K key;
    D data;
    unique_ptr<Node> left, right;
public:
    Node(const K& k, const D& d) : key(k), data(d) { }
};
template <typename K, typename D>
class Tree {
public:
    void insert(const K &key, const D& data);
    D* find(const K &key) { return findRec(key, root); }
private:
    D* findRec(const K &key, unique_ptr<Node<K,D>> &wo);
    unique_ptr<Node<K,D>> root;
};
template <typename K, typename D>
void Tree<K,D>::insert(const K& key, const D& data) {
    auto *current = &root;
    while(*current) { // solange unique_ptr was enthält
        auto &node = *(current->get());
        if (key < node.key) {
            current = &node.left;
        } else if (node.key < key) {
            current = &node.right;
        }
    }
    *current = std::make_unique<Node<K,D>>(key,data);
};
template <typename K, typename D>
D* Tree<K,D>::findRec(const K& key, unique_ptr<Node<K,D>> &wo) {
    if(!wo)
        return nullptr;
    auto &node = *(wo.get());
    if(key < node.key)
        return findRec(key, node.left);
    if(node.key < key)
        return findRec(key, node.right);
    return &node.data; // key == node.key
};
int main() {
    Tree<int,std::string> bt {};
    bt.insert(3, "drei");
    bt.insert(2, "zwei");
    bt.insert(4, "vier");
    auto wo = bt.find(7);
    if(wo==nullptr) cout<<"keine 7\n"; // Ausgabe: keine 7
    wo = bt.find(3);
    if(wo!=nullptr) cout<<*wo<<"\n";   // Ausgabe: drei
}

Godbolt Listing lst-0471-godb.cpp, https://godbolt.org/z/dTnxobz6v:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dTnxobz6v 
#include <memory> // unique_ptr
#include <string>
using std::unique_ptr; using std::cout;
template <typename K, typename D> class Tree; // Vorwärtsdeklaration
template <typename K, typename D>
class Node {
    friend class Tree<K,D>; // Zugriff auf Privates erlauben
    K key;
    D data;
    unique_ptr<Node> left, right;
public:
    Node(const K& k, const D& d) : key(k), data(d) { }
};
template <typename K, typename D>
class Tree {
public:
    void insert(const K &key, const D& data);
    D* find(const K &key) { return findRec(key, root); }
private:
    D* findRec(const K &key, unique_ptr<Node<K,D>> &wo);
    unique_ptr<Node<K,D>> root;
};
template <typename K, typename D>
void Tree<K,D>::insert(const K& key, const D& data) {
    auto *current = &root;
    while(*current) { // solange unique_ptr was enthält
        auto &node = *(current->get());
        if (key < node.key) {
            current = &node.left;
        } else if (node.key < key) {
            current = &node.right;
        }
    }
    *current = std::make_unique<Node<K,D>>(key,data);
};
template <typename K, typename D>
D* Tree<K,D>::findRec(const K& key, unique_ptr<Node<K,D>> &wo) {
    if(!wo)
        return nullptr;
    auto &node = *(wo.get());
    if(key < node.key)
        return findRec(key, node.left);
    if(node.key < key)
        return findRec(key, node.right);
    return &node.data; // key == node.key
};
int main() {
    Tree<int,std::string> bt {};
    bt.insert(3, "drei");
    bt.insert(2, "zwei");
    bt.insert(4, "vier");
    auto wo = bt.find(7);
    if(wo==nullptr) cout<<"keine 7\n"; // Ausgabe: keine 7
    wo = bt.find(3);
    if(wo!=nullptr) cout<<*wo<<"\n";   // Ausgabe: drei
}

Listing 18.3: Beim Erben können Sie angeben, was sichtbar werden soll.

Book listing lst-0473-book.cpp:

// https://godbolt.org/z/eKbK39nG1 
class Base {
public:
    int xPublic = 1;
protected:
    int xProtected = 2;
private:
    int xPrivate = 3;
};
class DerivedPublic : public Base {
    // xPublic wird 'public'
    // xProtected wird 'protected'
    // xPrivate ist hier nicht sichtbar
};
class DerivedProtected : protected Base {
    // xPublic wird 'protected'
    // xProtected wird 'protected'
    // xPrivate ist hier nicht sichtbar
};
class DerivedPrivate : private Base { // oder wenn nichts angegeben
    // xPublic wird 'private'
    // xProtected wird 'private'
    // xPrivate ist hier nicht sichtbar
};

Godbolt Listing lst-0473-godb.cpp, https://godbolt.org/z/eKbK39nG1:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eKbK39nG1 
class Base {
public:
    int xPublic = 1;
protected:
    int xProtected = 2;
private:
    int xPrivate = 3;
};
class DerivedPublic : public Base {
    // xPublic wird 'public'
    // xProtected wird 'protected'
    // xPrivate ist hier nicht sichtbar
};
class DerivedProtected : protected Base {
    // xPublic wird 'protected'
    // xProtected wird 'protected'
    // xPrivate ist hier nicht sichtbar
};
class DerivedPrivate : private Base { // oder wenn nichts angegeben
    // xPublic wird 'private'
    // xProtected wird 'private'
    // xPrivate ist hier nicht sichtbar
};

Listing 18.4: Ererbte Sichtbarkeiten, von außen betrachtet

Book listing lst-0474-book.cpp:

// https://godbolt.org/z/Pxqrjjqs8 
#include <iostream>
using std::cout; using std::ostream;
// … wie zuvor …
int main() {
    // öffentlich erben
    DerivedPublic dpu{};
    cout << dpu.xPublic << '\n';    // Ausgabe: 1
    cout << dpu.xProtected << '\n'; // kein Zugriff von außen
    // geschützt erben
    DerivedProtected dpt{};
    cout << dpt.xPublic << '\n';    // kein Zugriff von außen
    cout << dpt.xProtected << '\n'; // kein Zugriff von außen
    // private erben
    DerivedPrivate dpv{};
    cout << dpv.xPublic << '\n';    // kein Zugriff von außen
    cout << dpv.xProtected << '\n'; // kein Zugriff von außen
}

Godbolt Listing lst-0474-godb.cpp, https://godbolt.org/z/Pxqrjjqs8:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Pxqrjjqs8 
#include <iostream>
using std::cout; using std::ostream;
// … wie zuvor …
int main() {
    // öffentlich erben
    DerivedPublic dpu{};
    cout << dpu.xPublic << '\n';    // Ausgabe: 1
    cout << dpu.xProtected << '\n'; // kein Zugriff von außen
    // geschützt erben
    DerivedProtected dpt{};
    cout << dpt.xPublic << '\n';    // kein Zugriff von außen
    cout << dpt.xProtected << '\n'; // kein Zugriff von außen
    // private erben
    DerivedPrivate dpv{};
    cout << dpv.xPublic << '\n';    // kein Zugriff von außen
    cout << dpv.xProtected << '\n'; // kein Zugriff von außen
}

Listing 18.5: Ererbte Sichtbarkeiten für weitere Ableitungen

Book listing lst-0475-book.cpp:

// https://godbolt.org/z/xKEo38c4n 
#include <iostream>
using std::cout; using std::ostream;
// … wie zuvor …
struct Normalfall : public DerivedPublic {
    void drucke() {
        cout << xPublic;
        cout << xProtected;
    }
};
struct Spezialfall : public DerivedPrivate {
    void drucke() {
        cout << xPublic;                  //                 (ERR)  kein Zugriff
        cout << xProtected;               //                 (ERR)  kein Zugriff
    }
};
int main() {
    Normalfall n {};
    n.drucke(); // Ausgabe: 12
    Spezialfall s {};
    s.drucke();
}

Godbolt Listing lst-0475-godb.cpp, https://godbolt.org/z/xKEo38c4n:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xKEo38c4n 
#include <iostream>
using std::cout; using std::ostream;
// … wie zuvor …
struct Normalfall : public DerivedPublic {
    void drucke() {
        cout << xPublic;
        cout << xProtected;
    }
};
struct Spezialfall : public DerivedPrivate {
    void drucke() {
        cout << xPublic;                  //                 (ERR)  kein Zugriff
        cout << xProtected;               //                 (ERR)  kein Zugriff
    }
};
int main() {
    Normalfall n {};
    n.drucke(); // Ausgabe: 12
    Spezialfall s {};
    s.drucke();
}

Listing 18.6: In der Praxis nutzen Kindklassen privat Geerbtes indirekt.

Book listing lst-0476-book.cpp:

// https://godbolt.org/z/zMvWxT854 
#include <iostream>
using std::cout; using std::ostream;
class Basis {
    public: int daten = 5;
};
class Mitte : private Basis {
protected: void drucke() {
        cout << daten; // 'daten' ist hier privat geerbt
    }
};
class Letztendlich : public Mitte {
    public: void los() {
        // 'daten' ist nicht sichtbar
        drucke(); // 'drucke' ist geschützt sichtbar
    }
};
int main() {
    Letztendlich l {};
    l.los(); // Ausgabe: 5
}

Godbolt Listing lst-0476-godb.cpp, https://godbolt.org/z/zMvWxT854:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zMvWxT854 
#include <iostream>
using std::cout; using std::ostream;
class Basis {
    public: int daten = 5;
};
class Mitte : private Basis {
protected: void drucke() {
        cout << daten; // 'daten' ist hier privat geerbt
    }
};
class Letztendlich : public Mitte {
    public: void los() {
        // 'daten' ist nicht sichtbar
        drucke(); // 'drucke' ist geschützt sichtbar
    }
};
int main() {
    Letztendlich l {};
    l.los(); // Ausgabe: 5
}

Listing 18.7: »Hat-ein«-Beziehung mittels privater Vererbung

Book listing lst-0477-book.cpp:

// https://godbolt.org/z/zzT17q588 
class Motor {
public:
  Motor(int anzZylinder);
  void start();                  // Motor starten
};
class Auto : private Motor {     // Auto hat-einen Motor
public:
  Auto() : Motor{8} { }          // initialisiert ein Auto mit 8 Zylindern
  using Motor::start;            // startet Auto durch Starten des Motors
};

Godbolt Listing lst-0477-godb.cpp, https://godbolt.org/z/zzT17q588:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zzT17q588 
class Motor {
public:
  Motor(int anzZylinder);
  void start();                  // Motor starten
};
class Auto : private Motor {     // Auto hat-einen Motor
public:
  Auto() : Motor{8} { }          // initialisiert ein Auto mit 8 Zylindern
  using Motor::start;            // startet Auto durch Starten des Motors
};

Listing 18.8: »Hat-ein«-Beziehung mittels Mitglied

Book listing lst-0478-book.cpp:

// https://godbolt.org/z/8jGWTqh9z 
class Auto {
public:
  Auto() : motor_{8} { }           // initialisiert ein Auto mit 8 Zylindern
  void start() { motor_.start(); } // startet Auto durch Starten des Motors
private:
  Motor motor_;                    // Auto hat-einen Motor
};

Godbolt Listing lst-0478-godb.cpp, https://godbolt.org/z/8jGWTqh9z:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8jGWTqh9z 
class Auto {
public:
  Auto() : motor_{8} { }           // initialisiert ein Auto mit 8 Zylindern
  void start() { motor_.start(); } // startet Auto durch Starten des Motors
private:
  Motor motor_;                    // Auto hat-einen Motor
};

Listing 18.9: Eine Signaturklasse hat nur pur virtuelle Methoden.

Book listing lst-0479-book.cpp:

// https://godbolt.org/z/rW4oTPhrG 
struct Driver {
    virtual void init() = 0;
    virtual void done() = 0;
    virtual bool send(const char* data, unsigned len) = 0;
};

Godbolt Listing lst-0479-godb.cpp, https://godbolt.org/z/rW4oTPhrG:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rW4oTPhrG 
struct Driver {
    virtual void init() = 0;
    virtual void done() = 0;
    virtual bool send(const char* data, unsigned len) = 0;
};

Listing 18.10: Eine Signaturklasse macht eine gute Basisklasse.

Book listing lst-0480-book.cpp:

// https://godbolt.org/z/7xf6sxPqG 
#include <iostream>
using std::cout;
struct KeyboardDriver : public Driver {
    void init() override { cout << "Init Keyboard\n"; }
    void done() override { cout << "Done Keyboard\n"; }
    bool send(const char* data, unsigned int len) override {
        cout << "sending " << len << " bytes\n";
        return true;
    }
};
struct Computer {
    Driver &driver_;
    explicit Computer(Driver &driver) : driver_{driver} {
        driver_.init();
    }
    void run() {
        driver_.send("Hello", 5);
    }
    ~Computer() {
        driver_.done();
    }
    Computer(const Computer&) = delete;
};
int main() {
    KeyboardDriver keyboard {};
    Computer computer(keyboard); // Ausgabe: Init Keyboard
    computer.run();              // Ausgabe: sending 5 bytes
}                                // Ausgabe: Done Keyboard

Godbolt Listing lst-0480-godb.cpp, https://godbolt.org/z/7xf6sxPqG:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7xf6sxPqG 
#include <iostream>
using std::cout;
struct KeyboardDriver : public Driver {
    void init() override { cout << "Init Keyboard\n"; }
    void done() override { cout << "Done Keyboard\n"; }
    bool send(const char* data, unsigned int len) override {
        cout << "sending " << len << " bytes\n";
        return true;
    }
};
struct Computer {
    Driver &driver_;
    explicit Computer(Driver &driver) : driver_{driver} {
        driver_.init();
    }
    void run() {
        driver_.send("Hello", 5);
    }
    ~Computer() {
        driver_.done();
    }
    Computer(const Computer&) = delete;
};
int main() {
    KeyboardDriver keyboard {};
    Computer computer(keyboard); // Ausgabe: Init Keyboard
    computer.run();              // Ausgabe: sending 5 bytes
}                                // Ausgabe: Done Keyboard

Listing 18.11: Eine virtuelle Methode mit Implementierung »= 0« ist abstrakt.

Book listing lst-0481-book.cpp:

// https://godbolt.org/z/G1q964f1M 
#include <iostream>           // cout
#include <memory>             // unique_ptr
using std::cout;
class Driver {                // abstrakte Basisklasse
public:
    virtual void init() = 0;
    virtual void done() = 0;
    virtual void send(const std::string &data) = 0;
};
class ProductionDriver : public Driver {
public:
    void init() override { }
    void done() override { }
    void send(const std::string &data) override { cout << data << "\n"; }
};
class DebuggingDriver : public Driver {
   size_t countSend_ = 0;
public:
    void init() override {
        countSend_= 0; cout << "Ok, bin initialisiert.\n";
    }
    void done() override {
        cout << "send benutzt:" << countSend_ << " mal\n";
    }
    void send(const std::string &data) override {
        cout << "send("<<countSend_<<"):"<< data << "\n";
        ++countSend_;
    }
};
struct DriverWrapper {        // RAII-Wrapper für init() und done()
    Driver &driver_;
    explicit DriverWrapper(Driver& driver) : driver_(driver) { driver_.init(); }
    ~DriverWrapper() { driver_.done(); }
    DriverWrapper(const DriverWrapper&) = delete; // nicht kopieren
};

void doWork(Driver &driver) { // jemand, der flexibel einen beliebigen Driver nutzt
    DriverWrapper wrapper(driver);      // init() und done() aufrufen
    driver.send("Eine unerwartete Reise");
    driver.send("Smaugs Einoede");
}

int main() {
    // gleiche doWork, einmal mit Produktions- und einmal mit Debugging-Treiber
    ProductionDriver production{};
    doWork( production );
    DebuggingDriver debugging{};
    doWork( debugging );

    // üblichere Variante eines dynamisch erzeugten Treibers
    std::unique_ptr<Driver> driver{ new ProductionDriver{} };
    doWork( *driver );
}

Godbolt Listing lst-0481-godb.cpp, https://godbolt.org/z/G1q964f1M:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/G1q964f1M 
#include <iostream>           // cout
#include <memory>             // unique_ptr
using std::cout;
class Driver {                // abstrakte Basisklasse
public:
    virtual void init() = 0;
    virtual void done() = 0;
    virtual void send(const std::string &data) = 0;
};
class ProductionDriver : public Driver {
public:
    void init() override { }
    void done() override { }
    void send(const std::string &data) override { cout << data << "\n"; }
};
class DebuggingDriver : public Driver {
   size_t countSend_ = 0;
public:
    void init() override {
        countSend_= 0; cout << "Ok, bin initialisiert.\n";
    }
    void done() override {
        cout << "send benutzt:" << countSend_ << " mal\n";
    }
    void send(const std::string &data) override {
        cout << "send("<<countSend_<<"):"<< data << "\n";
        ++countSend_;
    }
};
struct DriverWrapper {        // RAII-Wrapper für init() und done()
    Driver &driver_;
    explicit DriverWrapper(Driver& driver) : driver_(driver) { driver_.init(); }
    ~DriverWrapper() { driver_.done(); }
    DriverWrapper(const DriverWrapper&) = delete; // nicht kopieren
};

void doWork(Driver &driver) { // jemand, der flexibel einen beliebigen Driver nutzt
    DriverWrapper wrapper(driver);      // init() und done() aufrufen
    driver.send("Eine unerwartete Reise");
    driver.send("Smaugs Einoede");
}

int main() {
    // gleiche doWork, einmal mit Produktions- und einmal mit Debugging-Treiber
    ProductionDriver production{};
    doWork( production );
    DebuggingDriver debugging{};
    doWork( debugging );

    // üblichere Variante eines dynamisch erzeugten Treibers
    std::unique_ptr<Driver> driver{ new ProductionDriver{} };
    doWork( *driver );
}

Listing 18.12: Multiple Vererbung heißt, mehrere Basisklassen zu haben.

Book listing lst-0483-book.cpp:

// https://godbolt.org/z/MPaYW1v5j 
#include <iostream>
using std::cout;
class Saeugetier {
public:
    void gebaere() { cout << "Geburt!\n"; }
};
class Fliegend {
public:
    void fliege() { cout << "Flug!\n"; }
};
class Fledermaus: public Saeugetier, public Fliegend {
public:
    void rufe() { cout << "Ultraschall!\n"; }
};
int main() {
    Fledermaus bruce{};
    bruce.gebaere();       // Ausgabe: Geburt!
    bruce.fliege();        // Ausgabe: Flug!
    bruce.rufe();          // Ausgabe: Ultraschall!
}

Godbolt Listing lst-0483-godb.cpp, https://godbolt.org/z/MPaYW1v5j:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MPaYW1v5j 
#include <iostream>
using std::cout;
class Saeugetier {
public:
    void gebaere() { cout << "Geburt!\n"; }
};
class Fliegend {
public:
    void fliege() { cout << "Flug!\n"; }
};
class Fledermaus: public Saeugetier, public Fliegend {
public:
    void rufe() { cout << "Ultraschall!\n"; }
};
int main() {
    Fledermaus bruce{};
    bruce.gebaere();       // Ausgabe: Geburt!
    bruce.fliege();        // Ausgabe: Flug!
    bruce.rufe();          // Ausgabe: Ultraschall!
}

Listing 18.13: Uhr und Kalender ergeben Uhr mit Kalender.

Book listing lst-0484-book.cpp:

// https://godbolt.org/z/M7TTvaPxx 
// Parameter müssen gültige Werte der jeweiligen Einheit sein.
#include <iostream> // ostream
#include <iomanip>  // setw, setfill
#include <format>
using std::ostream; using std::format;
class Clock {
protected:
    int h_, m_, s_;
public:
    Clock(int hours, int minutes, int seconds)
    : h_{hours}, m_{minutes}, s_{seconds} {}
    void setClock(int hours, int minutes, int seconds) {
        h_ = hours; m_ = minutes; s_ = seconds;
    }
    friend ostream& operator<<(ostream&os, const Clock& c) {
        return os << format("{:02}:{:02}:{:02}", c.h_, c.m_, c.s_);
    }
    void tick() { // +1 Sekunde
        if(s_ >= 59) {
            s_ = 0;
            if(m_ >= 59) {
                m_ = 0;
                if(h_ >= 23) h_ = 0;
                else { h_ += 1; }
            } else { m_ += 1; }
        } else { s_ += 1; }
    }
};

Godbolt Listing lst-0484-godb.cpp, https://godbolt.org/z/M7TTvaPxx:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M7TTvaPxx 
// Parameter müssen gültige Werte der jeweiligen Einheit sein.
#include <iostream> // ostream
#include <iomanip>  // setw, setfill
#include <format>
using std::ostream; using std::format;
class Clock {
protected:
    int h_, m_, s_;
public:
    Clock(int hours, int minutes, int seconds)
    : h_{hours}, m_{minutes}, s_{seconds} {}
    void setClock(int hours, int minutes, int seconds) {
        h_ = hours; m_ = minutes; s_ = seconds;
    }
    friend ostream& operator<<(ostream&os, const Clock& c) {
        return os << format("{:02}:{:02}:{:02}", c.h_, c.m_, c.s_);
    }
    void tick() { // +1 Sekunde
        if(s_ >= 59) {
            s_ = 0;
            if(m_ >= 59) {
                m_ = 0;
                if(h_ >= 23) h_ = 0;
                else { h_ += 1; }
            } else { m_ += 1; }
        } else { s_ += 1; }
    }
};

GodboltId:a5WxqjxEr

Book listing lst-0485-book.cpp:

// https://godbolt.org/z/a5WxqjxEr 
int main() {
    Clock clock{ 23, 59, 59 };
    std::cout << clock << '\n'; // Ausgabe: 23:59:59
    clock.tick();
    std::cout << clock << '\n'; // Ausgabe: 00:00:00
}

Godbolt Listing lst-0485-godb.cpp, https://godbolt.org/z/a5WxqjxEr:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a5WxqjxEr 
int main() {
    Clock clock{ 23, 59, 59 };
    std::cout << clock << '\n'; // Ausgabe: 23:59:59
    clock.tick();
    std::cout << clock << '\n'; // Ausgabe: 00:00:00
}

Listing 18.14: Eine einfache Kalenderklasse

Book listing lst-0486-book.cpp:

// https://godbolt.org/z/oe1hT9McG 
// … includes und usings …
struct Calendar {
    int y_, m_, d_;
    static const std::vector<int> mlens_;
    bool leapyear() const {
        if(y_ % 4 != 0) return false;
        if(y_ % 100 != 0) return true;
        if(y_ % 400 != 0) return false;
        return true;
    }
public:
    Calendar(int year, int month, int day)
    : y_{year}, m_{month}, d_{day} {}
    void setCalendar(int year, int month, int day) {
        y_ = year; m_ = month; d_ = day;
    }
    friend ostream& operator<<(ostream& os, const Calendar& c) {
        return os << format("{:04}-{:02}-{:02}", c.y_, c.m_, c.d_);
    }
    void advance() { // +1 day
        auto maxd = mlens_[m_-1]; // 0-basierter vector
        if(m_==2 && leapyear())
            maxd += 1;            // Februar im Schaltjahr
        if(d_ >= maxd) {
            d_ = 1;
            if(m_ >= 12) { m_ = 1; y_ += 1; }
            else { m_ += 1; }
        } else { d_ += 1; }
    }
};
const std::vector<int> Calendar::mlens_ = {31,28,31,30,31,30,31,31,30,31,30,31};

Godbolt Listing lst-0486-godb.cpp, https://godbolt.org/z/oe1hT9McG:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oe1hT9McG 
// … includes und usings …
struct Calendar {
    int y_, m_, d_;
    static const std::vector<int> mlens_;
    bool leapyear() const {
        if(y_ % 4 != 0) return false;
        if(y_ % 100 != 0) return true;
        if(y_ % 400 != 0) return false;
        return true;
    }
public:
    Calendar(int year, int month, int day)
    : y_{year}, m_{month}, d_{day} {}
    void setCalendar(int year, int month, int day) {
        y_ = year; m_ = month; d_ = day;
    }
    friend ostream& operator<<(ostream& os, const Calendar& c) {
        return os << format("{:04}-{:02}-{:02}", c.y_, c.m_, c.d_);
    }
    void advance() { // +1 day
        auto maxd = mlens_[m_-1]; // 0-basierter vector
        if(m_==2 && leapyear())
            maxd += 1;            // Februar im Schaltjahr
        if(d_ >= maxd) {
            d_ = 1;
            if(m_ >= 12) { m_ = 1; y_ += 1; }
            else { m_ += 1; }
        } else { d_ += 1; }
    }
};
const std::vector<int> Calendar::mlens_ = {31,28,31,30,31,30,31,31,30,31,30,31};

GodboltId:xf1xq8Ts3

Book listing lst-0487-book.cpp:

// https://godbolt.org/z/xf1xq8Ts3 
int main() {
    Calendar cal{ 2024, 2, 28 };
    std::cout << cal << '\n'; // Ausgabe: 2024-02-28
    cal.advance();
    std::cout << cal << '\n'; // Ausgabe: 2024-02-29
    cal.advance();
    std::cout << cal << '\n'; // Ausgabe: 2024-03-01
}

Godbolt Listing lst-0487-godb.cpp, https://godbolt.org/z/xf1xq8Ts3:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xf1xq8Ts3 
int main() {
    Calendar cal{ 2024, 2, 28 };
    std::cout << cal << '\n'; // Ausgabe: 2024-02-28
    cal.advance();
    std::cout << cal << '\n'; // Ausgabe: 2024-02-29
    cal.advance();
    std::cout << cal << '\n'; // Ausgabe: 2024-03-01
}

Listing 18.15: Die Kalenderuhr ist ein Kalender und eine Uhr.

Book listing lst-0488-book.cpp:

// https://godbolt.org/z/rh179GW3j 
class CalendarClock : public Clock, public Calendar {
public:
    CalendarClock(int y, int m, int d, int hh, int mm, int ss)
    : Calendar{y,m,d}, Clock{hh,mm,ss} {}
    void tick() {         // +1 Sekunde
        auto prev_h = h_;
        Clock::tick();    // Aufruf Basisklassenmethode
        if(h_ < prev_h) { // falls neuer Tag
            advance();    // … Kalender fortschreiten
        }
    }
    friend ostream& operator<<(ostream&os, const CalendarClock& cc) {
        operator<<(os, (Calendar&)cc) << " "; // Aufruf freie Funktion
        operator<<(os, (Clock&)cc);           // Aufruf freie Funktion
        return os;
    }
};

Godbolt Listing lst-0488-godb.cpp, https://godbolt.org/z/rh179GW3j:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rh179GW3j 
class CalendarClock : public Clock, public Calendar {
public:
    CalendarClock(int y, int m, int d, int hh, int mm, int ss)
    : Calendar{y,m,d}, Clock{hh,mm,ss} {}
    void tick() {         // +1 Sekunde
        auto prev_h = h_;
        Clock::tick();    // Aufruf Basisklassenmethode
        if(h_ < prev_h) { // falls neuer Tag
            advance();    // … Kalender fortschreiten
        }
    }
    friend ostream& operator<<(ostream&os, const CalendarClock& cc) {
        operator<<(os, (Calendar&)cc) << " "; // Aufruf freie Funktion
        operator<<(os, (Clock&)cc);           // Aufruf freie Funktion
        return os;
    }
};

GodboltId:P6nzT7EY4

Book listing lst-0489-book.cpp:

// https://godbolt.org/z/P6nzT7EY4 
int main() {
    CalendarClock cc{ 2024,2,29, 23,59,59 };
    std::cout << cc << '\n'; // Ausgabe: 2024-02-29 23:59:59
    cc.tick();
    std::cout << cc << '\n'; // Ausgabe: 2024-03-01 00:00:00
}

Godbolt Listing lst-0489-godb.cpp, https://godbolt.org/z/P6nzT7EY4:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/P6nzT7EY4 
int main() {
    CalendarClock cc{ 2024,2,29, 23,59,59 };
    std::cout << cc << '\n'; // Ausgabe: 2024-02-29 23:59:59
    cc.tick();
    std::cout << cc << '\n'; // Ausgabe: 2024-03-01 00:00:00
}

Listing 18.16: Mit multipler Vererbung kann sich der Wert eines Zeigers ändern.

Book listing lst-0492-book.cpp:

// https://godbolt.org/z/oc7jsbrEK 
#include <iostream>
using std::cout;
struct Base1 {
    virtual void f1() {}
};
struct Base2 {
    virtual void f2() {}
};
struct Derived : public Base1, public Base2 {
    virtual void g() {};
};
void vergleich(void* a, void* b) {
    cout << (a==b ? "identisch\n" : "unterschiedlich\n");
}
int main() {
    Derived d{};
    auto *pd = &d;
    cout << pd << '\n';       // zum Beispiel 0x1000
    auto pb1 = static_cast<Base1*>(pd);
    cout << pb1 << '\n';      // immer noch 0x1000
    auto pb2 = static_cast<Base2*>(pd);
    cout << pb2 << '\n';      // jetzt 0x1008 !
    cout << (pd==pb1 ? "gleich\n" : "verschieden\n"); // Ausgabe: gleich
    cout << (pd==pb2 ? "gleich\n" : "verschieden\n"); // Ausgabe: gleich
    vergleich(pb1, pd);       // Ausgabe: identisch
    vergleich(pb2, pd);       // Ausgabe: unterschiedlich
}

Godbolt Listing lst-0492-godb.cpp, https://godbolt.org/z/oc7jsbrEK:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oc7jsbrEK 
#include <iostream>
using std::cout;
struct Base1 {
    virtual void f1() {}
};
struct Base2 {
    virtual void f2() {}
};
struct Derived : public Base1, public Base2 {
    virtual void g() {};
};
void vergleich(void* a, void* b) {
    cout << (a==b ? "identisch\n" : "unterschiedlich\n");
}
int main() {
    Derived d{};
    auto *pd = &d;
    cout << pd << '\n';       // zum Beispiel 0x1000
    auto pb1 = static_cast<Base1*>(pd);
    cout << pb1 << '\n';      // immer noch 0x1000
    auto pb2 = static_cast<Base2*>(pd);
    cout << pb2 << '\n';      // jetzt 0x1008 !
    cout << (pd==pb1 ? "gleich\n" : "verschieden\n"); // Ausgabe: gleich
    cout << (pd==pb2 ? "gleich\n" : "verschieden\n"); // Ausgabe: gleich
    vergleich(pb1, pd);       // Ausgabe: identisch
    vergleich(pb2, pd);       // Ausgabe: unterschiedlich
}

Listing 18.17: Das Beobachter-Muster mit multipler Vererbung

Book listing lst-0493-book.cpp:

// https://godbolt.org/z/EnE7Y886M 
#include <iostream>
#include <vector>
using std::cout;
// == Beobachter-Entwurfsmuster ==
struct Observer {
    virtual void update() = 0;
};
class Subject {
    std::vector<Observer*> observers_; // not owning pointers
protected:
    void notify() {
        for (auto o : observers_)
            o->update();
    }
public:
    void addObserver(Observer* o) {
        observers_.push_back(o);
    }
};
// == konkrete Klasse ==
struct MyThing {
    int calc() { return 1+1; }
};
// == zusammenbringen ==
struct MyObservableThing : public MyThing, public Subject {
    int calc() {
        notify();
        return MyThing::calc();
    }
};
// == etwas beobachten ==
struct MyObserver : public Observer {
    void update() override {
        cout << "observed\n";
    }
};
int main() {
    MyObserver myObserver{};
    MyObservableThing myObservableThing{};
    myObservableThing.addObserver(&myObserver);
    auto result = myObservableThing.calc(); // Ausgabe: observed
}

Godbolt Listing lst-0493-godb.cpp, https://godbolt.org/z/EnE7Y886M:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/EnE7Y886M 
#include <iostream>
#include <vector>
using std::cout;
// == Beobachter-Entwurfsmuster ==
struct Observer {
    virtual void update() = 0;
};
class Subject {
    std::vector<Observer*> observers_; // not owning pointers
protected:
    void notify() {
        for (auto o : observers_)
            o->update();
    }
public:
    void addObserver(Observer* o) {
        observers_.push_back(o);
    }
};
// == konkrete Klasse ==
struct MyThing {
    int calc() { return 1+1; }
};
// == zusammenbringen ==
struct MyObservableThing : public MyThing, public Subject {
    int calc() {
        notify();
        return MyThing::calc();
    }
};
// == etwas beobachten ==
struct MyObserver : public Observer {
    void update() override {
        cout << "observed\n";
    }
};
int main() {
    MyObserver myObserver{};
    MyObservableThing myObservableThing{};
    myObservableThing.addObserver(&myObserver);
    auto result = myObservableThing.calc(); // Ausgabe: observed
}

Listing 18.18: Ein einfaches Beispiel mit virtueller Vererbung

Book listing lst-0494-book.cpp:

// https://godbolt.org/z/8jYeYPs7W 
#include <iostream>
using std::cout;
class Base {
public:
  int data_ = 0;
};
class Derived1 : public virtual Base {
};
class Derived2 : public virtual Base {
};
class DerivedDerived : public Derived1, public Derived2 {
public:
  void method() {
     data_ = 1;  // eindeutig, denn es gibt nur ein data_
  }
};
void ausgabe(const DerivedDerived &dd) {
    cout << dd.data_
        << (((Derived1&)dd).data_)
        << (((Derived2&)dd).data_)
        << (((Base&)dd).data_) << '\n';
}
int main() {
  DerivedDerived dd{};
  ausgabe(dd);   // Ausgabe: 0000
  dd.method();   // setzt data_ auf 1
  ausgabe(dd);   // Ausgabe: 1111
}

Godbolt Listing lst-0494-godb.cpp, https://godbolt.org/z/8jYeYPs7W:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8jYeYPs7W 
#include <iostream>
using std::cout;
class Base {
public:
  int data_ = 0;
};
class Derived1 : public virtual Base {
};
class Derived2 : public virtual Base {
};
class DerivedDerived : public Derived1, public Derived2 {
public:
  void method() {
     data_ = 1;  // eindeutig, denn es gibt nur ein data_
  }
};
void ausgabe(const DerivedDerived &dd) {
    cout << dd.data_
        << (((Derived1&)dd).data_)
        << (((Derived2&)dd).data_)
        << (((Base&)dd).data_) << '\n';
}
int main() {
  DerivedDerived dd{};
  ausgabe(dd);   // Ausgabe: 0000
  dd.method();   // setzt data_ auf 1
  ausgabe(dd);   // Ausgabe: 1111
}

Listing 18.19: Effektiv ruft nutzer() hier eine Schwestermethode auf.

Book listing lst-0495-book.cpp:

// https://godbolt.org/z/s9xnn7c5j 
#include <iostream>
using std::cout;
struct Base { // abstrakte Klasse
  virtual void anbieter() = 0;
  virtual void nutzer() = 0;
};
struct Derived1 : public virtual Base { // noch abstrakt
  virtual void nutzer() override { anbieter(); }
};
struct Derived2 : public virtual Base { // noch abstrakt
  virtual void anbieter() override { cout << "Derived2::anbieter!\n"; }
};
struct DerivedDerived : public Derived1, public Derived2 { // konkret
};
int main() {
  DerivedDerived dd{};
  DerivedDerived *pdd = &dd;
  Derived1* pd1 = pdd; // Cast innerhalb der Hierarchie
  Derived2* pd2 = pdd; // Cast innerhalb der Hierarchie
  pdd->nutzer();       // Ausgabe: Derived2::anbieter()!
  pd1->nutzer();       // Ausgabe: Derived2::anbieter()!
  pd2->nutzer();       // Ausgabe: Derived2::anbieter()!
}

Godbolt Listing lst-0495-godb.cpp, https://godbolt.org/z/s9xnn7c5j:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/s9xnn7c5j 
#include <iostream>
using std::cout;
struct Base { // abstrakte Klasse
  virtual void anbieter() = 0;
  virtual void nutzer() = 0;
};
struct Derived1 : public virtual Base { // noch abstrakt
  virtual void nutzer() override { anbieter(); }
};
struct Derived2 : public virtual Base { // noch abstrakt
  virtual void anbieter() override { cout << "Derived2::anbieter!\n"; }
};
struct DerivedDerived : public Derived1, public Derived2 { // konkret
};
int main() {
  DerivedDerived dd{};
  DerivedDerived *pdd = &dd;
  Derived1* pd1 = pdd; // Cast innerhalb der Hierarchie
  Derived2* pd2 = pdd; // Cast innerhalb der Hierarchie
  pdd->nutzer();       // Ausgabe: Derived2::anbieter()!
  pd1->nutzer();       // Ausgabe: Derived2::anbieter()!
  pd2->nutzer();       // Ausgabe: Derived2::anbieter()!
}

Listing 18.20: Einen literalen Datentyp erstellen Sie mit einem constexpr-Konstruktor.

Book listing lst-0498-book.cpp:

// https://godbolt.org/z/Kvfx9Yeox 
#include <array>
class Value {
    int val_;
public:
    constexpr Value(int val) : val_{val} {};
    constexpr int get() const { return val_; }
};

constexpr Value fuenf{5}; // geht, Value ist literaler Datentyp

std::array<int,fuenf.get()> data; // geht, get ist constexpr

Godbolt Listing lst-0498-godb.cpp, https://godbolt.org/z/Kvfx9Yeox:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Kvfx9Yeox 
#include <array>
class Value {
    int val_;
public:
    constexpr Value(int val) : val_{val} {};
    constexpr int get() const { return val_; }
};

constexpr Value fuenf{5}; // geht, Value ist literaler Datentyp

std::array<int,fuenf.get()> data; // geht, get ist constexpr

Listing 18.21: Benutzerdefinierte Literale sind besonders nützlich mit literalen Datentypen.

Book listing lst-0499-book.cpp:

// https://godbolt.org/z/r1vYc7r5j 
#include <array>
#include <iostream>
#include <type_traits> // is_literal_type
class Value {
    int val_;
public:
    constexpr Value(int val) : val_{val} {};
    constexpr operator int() const { return val_; }
};
namespace lit {
    constexpr Value operator"" _val(const char*, size_t sz) { 
      return Value(sz); }
}
struct Nope {
    constexpr Nope() {};
    virtual ~Nope() {};                // nicht trivialer Destruktor
};
int main() {
    using namespace lit;
    constexpr Value fuenf{5};
    std::array<int,"11111"_val> data;  // benutzerdefiniertes Literal verwenden
    std::cout << data.size() << '\n';                        // Ausgabe: 5
    std::cout << std::boolalpha;
    std::cout << std::is_literal_type<Value>::value << '\n'; // Ausgabe: true
    std::cout << std::is_literal_type<Nope>::value << '\n';  // Ausgabe: false
}

Godbolt Listing lst-0499-godb.cpp, https://godbolt.org/z/r1vYc7r5j:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/r1vYc7r5j 
#include <array>
#include <iostream>
#include <type_traits> // is_literal_type
class Value {
    int val_;
public:
    constexpr Value(int val) : val_{val} {};
    constexpr operator int() const { return val_; }
};
namespace lit {
    constexpr Value operator"" _val(const char*, size_t sz) { 
      return Value(sz); }
}
struct Nope {
    constexpr Nope() {};
    virtual ~Nope() {};                // nicht trivialer Destruktor
};
int main() {
    using namespace lit;
    constexpr Value fuenf{5};
    std::array<int,"11111"_val> data;  // benutzerdefiniertes Literal verwenden
    std::cout << data.size() << '\n';                        // Ausgabe: 5
    std::cout << std::boolalpha;
    std::cout << std::is_literal_type<Value>::value << '\n'; // Ausgabe: true
    std::cout << std::is_literal_type<Nope>::value << '\n';  // Ausgabe: false
}

Listing 19.1: Call-by-Reference als Basis für Polymorphie

Book listing lst-0501-book.cpp:

// https://godbolt.org/z/scqTWvhsv 
class Auto { };
  class VwBulli : public Auto { };
  class Ente : public Auto { };
void lassFahren(Auto wagen) { }   //             (ERR)  Wertparameter kopiert nur Basisklasse
void lassBremsen(Auto &wagen) { } // Referenzparameter
void lassHupen(Auto *wagen) { }   // Übergabe als Zeiger
int main() {
    VwBulli bulli{  };            // automatische Variable
    Auto *ente = new Ente{  };    // dynamisch verwaltet
    lassFahren(bulli);            //             (ERR)  wird zum Auto kopiert
    lassFahren(*ente);            //             (ERR)  wird zum Auto kopiert
    lassBremsen(bulli);           // bleibt VwBulli
    lassBremsen(*ente);           // bleibt Ente
    lassHupen(&bulli);            // bleibt VwBulli
    lassHupen(ente);              // bleibt Ente
}

Godbolt Listing lst-0501-godb.cpp, https://godbolt.org/z/scqTWvhsv:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/scqTWvhsv 
class Auto { };
  class VwBulli : public Auto { };
  class Ente : public Auto { };
void lassFahren(Auto wagen) { }   //             (ERR)  Wertparameter kopiert nur Basisklasse
void lassBremsen(Auto &wagen) { } // Referenzparameter
void lassHupen(Auto *wagen) { }   // Übergabe als Zeiger
int main() {
    VwBulli bulli{  };            // automatische Variable
    Auto *ente = new Ente{  };    // dynamisch verwaltet
    lassFahren(bulli);            //             (ERR)  wird zum Auto kopiert
    lassFahren(*ente);            //             (ERR)  wird zum Auto kopiert
    lassBremsen(bulli);           // bleibt VwBulli
    lassBremsen(*ente);           // bleibt Ente
    lassHupen(&bulli);            // bleibt VwBulli
    lassHupen(ente);              // bleibt Ente
}

Listing 19.2: Die Klasse Buch dient den Akteuren Leser und Bibliothekar.

Book listing lst-0502-book.cpp:

// https://godbolt.org/z/fdh4n5x84 
struct Buch {
   auto getTitel() { return Titel{"Das C++ Handbuch"s}; }
   auto getAutor() { return Autor{"Torsten T. Will"s}; }
   auto umblaettern() { return /* Referenz zur nächsten Seite */ 42; }
   auto getSeite() { return "aktueller Seiteninhalt"; }
   auto getStandort() { return /* Regalnummer/Buchnummer */ 73; }
};

Godbolt Listing lst-0502-godb.cpp, https://godbolt.org/z/fdh4n5x84:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fdh4n5x84 
struct Buch {
   auto getTitel() { return Titel{"Das C++ Handbuch"s}; }
   auto getAutor() { return Autor{"Torsten T. Will"s}; }
   auto umblaettern() { return /* Referenz zur nächsten Seite */ 42; }
   auto getSeite() { return "aktueller Seiteninhalt"; }
   auto getStandort() { return /* Regalnummer/Buchnummer */ 73; }
};

Listing 19.3: Die Änderungen eines Akteurs spielen sich meist nur noch in einer Klasse ab.

Book listing lst-0503-book.cpp:

// https://godbolt.org/z/Tq9xbGxs4 
struct Buch {
   auto getTitel() { return Titel{"Das C++ Handbuch"s}; }
   auto getAutor() { return Autor{"Torsten T. Will"s}; }
   auto umblaettern() { return /* Referenz zur nächsten Seite */ 42; }
   auto getSeite() { return "aktueller Seiteninhalt"; }
   auto getStandort() { return /* Regalnummer/Buchnummer */ 73; }
};
struct BuchFinder {
    Katalog katalog;
    auto finde(Buch& buch) { /* Regalnummer/Buchnummer */
        katalog.findeBuchNach(buch.getTitel(), buch.getAutor());
    }
};

Godbolt Listing lst-0503-godb.cpp, https://godbolt.org/z/Tq9xbGxs4:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Tq9xbGxs4 
struct Buch {
   auto getTitel() { return Titel{"Das C++ Handbuch"s}; }
   auto getAutor() { return Autor{"Torsten T. Will"s}; }
   auto umblaettern() { return /* Referenz zur nächsten Seite */ 42; }
   auto getSeite() { return "aktueller Seiteninhalt"; }
   auto getStandort() { return /* Regalnummer/Buchnummer */ 73; }
};
struct BuchFinder {
    Katalog katalog;
    auto finde(Buch& buch) { /* Regalnummer/Buchnummer */
        katalog.findeBuchNach(buch.getTitel(), buch.getAutor());
    }
};

Listing 19.4: Folgt nicht dem Open/Closed Principle

Book listing lst-0504-book.cpp:

// https://godbolt.org/z/vxTsveGjT 
#include <vector>
#include <memory> // unique_ptr
#include <iostream> // cout
enum class ShapeTag { CIRC, RECT };
struct Shape { // Data
    ShapeTag tag_;
    double v1_, v2_;
    Shape(double w, double h) : tag_{ShapeTag::RECT}, v1_{w}, v2_{h} {}
    Shape(double r) : tag_{ShapeTag::CIRC}, v1_{r}, v2_{0} {}
};
class AreaCalculator { // Logic
public:
    double area(const std::vector<std::unique_ptr<Shape>> &shapes) const {
        double result = 0;
        for(auto &shape :  shapes) {
            switch(shape->tag_) {
            case ShapeTag::CIRC:
                 result += 3.1415 * shape->v1_ * shape->v1_;
                 break;
            case ShapeTag::RECT:
                 result += shape->v1_*shape->v2_;
                 break;
            }
        }
        return result;
    }
};
int main() {
    std::vector<std::unique_ptr<Shape>> data{};
    data.push_back(std::make_unique<Shape>(10.));     // ein Kreis
    data.push_back(std::make_unique<Shape>(4., 6.));  // ein Rechteck
    // rechnen
    AreaCalculator calc{};
    std::cout  << calc.area( data ) << "\n";
}

Godbolt Listing lst-0504-godb.cpp, https://godbolt.org/z/vxTsveGjT:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vxTsveGjT 
#include <vector>
#include <memory> // unique_ptr
#include <iostream> // cout
enum class ShapeTag { CIRC, RECT };
struct Shape { // Data
    ShapeTag tag_;
    double v1_, v2_;
    Shape(double w, double h) : tag_{ShapeTag::RECT}, v1_{w}, v2_{h} {}
    Shape(double r) : tag_{ShapeTag::CIRC}, v1_{r}, v2_{0} {}
};
class AreaCalculator { // Logic
public:
    double area(const std::vector<std::unique_ptr<Shape>> &shapes) const {
        double result = 0;
        for(auto &shape :  shapes) {
            switch(shape->tag_) {
            case ShapeTag::CIRC:
                 result += 3.1415 * shape->v1_ * shape->v1_;
                 break;
            case ShapeTag::RECT:
                 result += shape->v1_*shape->v2_;
                 break;
            }
        }
        return result;
    }
};
int main() {
    std::vector<std::unique_ptr<Shape>> data{};
    data.push_back(std::make_unique<Shape>(10.));     // ein Kreis
    data.push_back(std::make_unique<Shape>(4., 6.));  // ein Rechteck
    // rechnen
    AreaCalculator calc{};
    std::cout  << calc.area( data ) << "\n";
}

Listing 19.5: Folgt dem OCP

Book listing lst-0505-book.cpp:

// https://godbolt.org/z/YWE4bT4zG 
#include <vector>
#include <memory>    // unique_ptr
#include <iostream>  // cout
struct Shape {
    virtual ~Shape() {}
    virtual double area() const = 0; // abstrakt
};
class Rectangle : public Shape {
    double w_, h_;
public:
    Rectangle(double w, double h) : w_{w}, h_{h} {}
    double area() const override { return w_ * h_; }
};
class Circle : public Shape {
    double r_;
public:
    Circle(double r) : r_{r} {}
    double area() const override { return 3.1415*r_* r_; }
};
class AreaCalculator { // Logic
public:
    double area(const std::vector<std::unique_ptr<Shape>> &shapes) const {
        double result = 0;
        for(auto &shape :  shapes) {
            result += shape->area();
        }
        return result;
    }
};
int main() {
    std::vector<std::unique_ptr<Shape>> data{};
    data.push_back(std::make_unique<Circle>(10.));        // ein Kreis
    data.push_back(std::make_unique<Rectangle>(4., 6.));  // ein Rechteck
    // rechnen
    AreaCalculator calc{};
    std::cout  << calc.area( data ) << "\n";
}

Godbolt Listing lst-0505-godb.cpp, https://godbolt.org/z/YWE4bT4zG:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YWE4bT4zG 
#include <vector>
#include <memory>    // unique_ptr
#include <iostream>  // cout
struct Shape {
    virtual ~Shape() {}
    virtual double area() const = 0; // abstrakt
};
class Rectangle : public Shape {
    double w_, h_;
public:
    Rectangle(double w, double h) : w_{w}, h_{h} {}
    double area() const override { return w_ * h_; }
};
class Circle : public Shape {
    double r_;
public:
    Circle(double r) : r_{r} {}
    double area() const override { return 3.1415*r_* r_; }
};
class AreaCalculator { // Logic
public:
    double area(const std::vector<std::unique_ptr<Shape>> &shapes) const {
        double result = 0;
        for(auto &shape :  shapes) {
            result += shape->area();
        }
        return result;
    }
};
int main() {
    std::vector<std::unique_ptr<Shape>> data{};
    data.push_back(std::make_unique<Circle>(10.));        // ein Kreis
    data.push_back(std::make_unique<Rectangle>(4., 6.));  // ein Rechteck
    // rechnen
    AreaCalculator calc{};
    std::cout  << calc.area( data ) << "\n";
}

GodboltId:rc67xWWfT

Book listing lst-0506-book.cpp:

// https://godbolt.org/z/rc67xWWfT 
#include <iostream>
struct Point { int x, y; };
class Rectangle {
protected:
    Point origin_;  int width_;  int height_;
public:
    Rectangle(Point o, int w, int h) : origin_{o}, width_{w}, height_{h} {}
    virtual void setHeight(int height) { height_ = height; }
    virtual int  getHeight() const { return height_; }
    virtual void setWidth(int width) { width_ = width; }
    virtual int getWidth() const { return width_; }
    virtual int getArea() const { return width_ * height_; }
};
class Square : public Rectangle {
public:
    Square(Point o, int wh) : Rectangle{o, wh, wh} {}
    void setHeight(int wh) override { width_ = height_ = wh; }
    void setWidth(int wh) override { width_ = height_ = wh; }
};
void areaCheck(Rectangle &rect) {
    rect.setWidth(5);
    rect.setHeight(4);
    auto areaValue = rect.getArea();
    if(areaValue != 20) {
        std::cout << "error!\n";
    } else {
        std::cout << "all fine\n";
    }
}
int main() {
    Rectangle rect{ {0,0}, 0,0 };
    areaCheck( rect );          // Ausgabe: all fine
    Square square{ {0,0}, 0 };
    areaCheck( square );        // Ausgabe: error!
}

Godbolt Listing lst-0506-godb.cpp, https://godbolt.org/z/rc67xWWfT:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rc67xWWfT 
#include <iostream>
struct Point { int x, y; };
class Rectangle {
protected:
    Point origin_;  int width_;  int height_;
public:
    Rectangle(Point o, int w, int h) : origin_{o}, width_{w}, height_{h} {}
    virtual void setHeight(int height) { height_ = height; }
    virtual int  getHeight() const { return height_; }
    virtual void setWidth(int width) { width_ = width; }
    virtual int getWidth() const { return width_; }
    virtual int getArea() const { return width_ * height_; }
};
class Square : public Rectangle {
public:
    Square(Point o, int wh) : Rectangle{o, wh, wh} {}
    void setHeight(int wh) override { width_ = height_ = wh; }
    void setWidth(int wh) override { width_ = height_ = wh; }
};
void areaCheck(Rectangle &rect) {
    rect.setWidth(5);
    rect.setHeight(4);
    auto areaValue = rect.getArea();
    if(areaValue != 20) {
        std::cout << "error!\n";
    } else {
        std::cout << "all fine\n";
    }
}
int main() {
    Rectangle rect{ {0,0}, 0,0 };
    areaCheck( rect );          // Ausgabe: all fine
    Square square{ {0,0}, 0 };
    areaCheck( square );        // Ausgabe: error!
}

Listing 19.6: Kovarianz für Rückgabetypen

Book listing lst-0507-book.cpp:

// https://godbolt.org/z/Gxh4edc8n 
using std::vector;

struct B {};
struct D : public B {};

struct Base1 {
    virtual B& func();
};
struct Derived1 : public Base1 {
    virtual D& func() override;         // D& ist kovariant
};
struct Base2 {
    virtual B& func();
};
struct Derived2 : public Base2 {
    virtual D func() override;          //                     (ERR)  D ist nicht kovariant
};
struct Base3 {
    virtual vector<B> func();
};
struct Derived3 : public Base3 {
    virtual vector<D>& func() override; //                     (ERR)  vector<D>& ist nicht kovariant
};
struct Base4 {
    virtual vector<B*>& func();
};
struct Derived4 : public Base4 {
    virtual vector<D*>& func() override; //                     (ERR)  anderer Typ, nicht kovariant
};

Godbolt Listing lst-0507-godb.cpp, https://godbolt.org/z/Gxh4edc8n:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Gxh4edc8n 
using std::vector;

struct B {};
struct D : public B {};

struct Base1 {
    virtual B& func();
};
struct Derived1 : public Base1 {
    virtual D& func() override;         // D& ist kovariant
};
struct Base2 {
    virtual B& func();
};
struct Derived2 : public Base2 {
    virtual D func() override;          //                     (ERR)  D ist nicht kovariant
};
struct Base3 {
    virtual vector<B> func();
};
struct Derived3 : public Base3 {
    virtual vector<D>& func() override; //                     (ERR)  vector<D>& ist nicht kovariant
};
struct Base4 {
    virtual vector<B*>& func();
};
struct Derived4 : public Base4 {
    virtual vector<D*>& func() override; //                     (ERR)  anderer Typ, nicht kovariant
};

GodboltId:4536hxvEK

Book listing lst-0510-book.cpp:

// https://godbolt.org/z/4536hxvEK 
int value = 42;
int& valueRef = value; // Referenz; kein Adressoperator & nötig
valueRef = 18;         // kein Dereferenzierungsoperator * nötig
cout << value << "\n"; // Ausgabe: 18

Godbolt Listing lst-0510-godb.cpp, https://godbolt.org/z/4536hxvEK:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4536hxvEK 
int value = 42;
int& valueRef = value; // Referenz; kein Adressoperator & nötig
valueRef = 18;         // kein Dereferenzierungsoperator * nötig
cout << value << "\n"; // Ausgabe: 18

Listing 20.1: Zeiger können im Laufe ihres Lebens neue Adressen zugewiesen bekommen.

Book listing lst-0511-book.cpp:

// https://godbolt.org/z/qTxs8bTdz 
#include <vector>
#include <iostream>
using std::vector; using std::cout; using std::ostream;
ostream& printVector(ostream& os, const vector<int> &arg) { // Hilfsfunktion
    for(int w : arg) os << w << " "; return os;
}
int main() {
    vector<int> werte{ };
    werte.reserve(50);                      // Platz für 50 Werte garantieren
    int *groesstes = nullptr;               // mit besonderem Wert initialisieren
    for(int w : { 20, 2, 30, 15, 81, 104, 70, 2, }) {
        werte.push_back(w);
        if(!groesstes || *groesstes < w ) { // dereferenzieren zum Wert
            groesstes = &(werte.back());    // neue Adresse merken; deshalb nicht '*'
        }
    }
    printVector(cout, werte) << "\n";       // Ausgabe: 20 2 30 15 81 104 70 2
    // groesstes enthält nun die Adresse der 104:
    *groesstes = -999;                // dereferenzieren; also Wert überschreiben
    printVector(cout, werte) << "\n";       // Ausgabe: 20 2 30 15 81 –999 70 2
}

Godbolt Listing lst-0511-godb.cpp, https://godbolt.org/z/qTxs8bTdz:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qTxs8bTdz 
#include <vector>
#include <iostream>
using std::vector; using std::cout; using std::ostream;
ostream& printVector(ostream& os, const vector<int> &arg) { // Hilfsfunktion
    for(int w : arg) os << w << " "; return os;
}
int main() {
    vector<int> werte{ };
    werte.reserve(50);                      // Platz für 50 Werte garantieren
    int *groesstes = nullptr;               // mit besonderem Wert initialisieren
    for(int w : { 20, 2, 30, 15, 81, 104, 70, 2, }) {
        werte.push_back(w);
        if(!groesstes || *groesstes < w ) { // dereferenzieren zum Wert
            groesstes = &(werte.back());    // neue Adresse merken; deshalb nicht '*'
        }
    }
    printVector(cout, werte) << "\n";       // Ausgabe: 20 2 30 15 81 104 70 2
    // groesstes enthält nun die Adresse der 104:
    *groesstes = -999;                // dereferenzieren; also Wert überschreiben
    printVector(cout, werte) << "\n";       // Ausgabe: 20 2 30 15 81 –999 70 2
}

Listing 20.2: Eine Rückgabe als Wert kann eine Kopie erzeugen.

Book listing lst-0514-book.cpp:

Planet erzeugePlanet(const Event &evt) { // Rückgabe als Wert
    Planet result{"Erde"};               // Stackobjekt
    result.setLocation(evt.getPosition());
    return result;                       // Rückgabe erzeugt (potenziell) Kopie
}

Listing 20.3: Eine Rückgabe als Zeiger kopiert nur den Zeiger, nicht das Objekt.

Book listing lst-0515-book.cpp:

// Rückgabe als (smarter) Pointer:
unique_ptr<Planet> erzeugePlanet(const Event &evt) {
    unique_ptr<Planet> result{ new Planet{"Venus"} };  // Heapobjekt
    result->setLocation(evt.getPosition());
    return result; // reicht Adresse weiter
}

Listing 20.4: In den folgenden Beispielen verwende ich Image als Klasse, zu der ich einen Zeiger haben will.

Book listing lst-0517-book.cpp:

// https://godbolt.org/z/ehhGPjabz 
#include <string>
#include <vector>
class Image {
    std::vector<char> bilddaten_;
public:
    explicit Image(const std::string& filename) { /* Bild laden */ }
    void draw() const { /* Bild malen */ };
};

Godbolt Listing lst-0517-godb.cpp, https://godbolt.org/z/ehhGPjabz:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ehhGPjabz 
#include <string>
#include <vector>
class Image {
    std::vector<char> bilddaten_;
public:
    explicit Image(const std::string& filename) { /* Bild laden */ }
    void draw() const { /* Bild malen */ };
};

Listing 20.5: unique_ptr als Datenfeld, Rückgabewert und lokale Variable

Book listing lst-0518-book.cpp:

// https://godbolt.org/z/Eh9ox6x9E 
#include <memory>                        // unique_ptr
#include <string>
#include <iostream>
using std::unique_ptr; using std::string;
class Component { };                     // Dummy-Fensterhierarchie
class Label : public Component { };
class Textfield : public Component { };
class Button : public Component {
public:
    int id_; // ID zur Unterscheidung der Buttons
    explicit Button(int id) : id_{id} {}
};
class Window { };
class MyDialog : public Window {
    string title_;
    unique_ptr<Label> lblVorname_{new Label{}};         // lauter Datenfelder
    unique_ptr<Textfield> txtVorname_{new Textfield{}}; // … an die Lebensdauer
    unique_ptr<Label> lblNachname_{new Label{}};        // … der Klasse gebunden
    unique_ptr<Textfield> txtNachname_{new Textfield{}};
    unique_ptr<Button> btnOk_{new Button{1}};
    unique_ptr<Button> btnAbbrechen_{new Button{2}};
public:
    explicit MyDialog(const string& title) : title_{title} {}
    unique_ptr<Button> showModal()
        { return std::move(btnOk_); }    // Platzhaltercode; OK gedrückt
};
unique_ptr<MyDialog> createDialog() {
    return unique_ptr<MyDialog>{ // temporärer Wert
        new MyDialog{"Bitte Namen eingeben"}};
}
int showDialog() {
    unique_ptr<MyDialog> dialog = createDialog();       // lokale Variable
    unique_ptr<Button> gedrueckt = dialog->showModal(); // Rückgabewert
    return gedrueckt->id_;
}
int main() {
    int gedrueckt_id = showDialog();
    if(gedrueckt_id == 1) {
        std::cout << "Danke, dass Sie OK gedrueckt haben\n";
    }
}

Godbolt Listing lst-0518-godb.cpp, https://godbolt.org/z/Eh9ox6x9E:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Eh9ox6x9E 
#include <memory>                        // unique_ptr
#include <string>
#include <iostream>
using std::unique_ptr; using std::string;
class Component { };                     // Dummy-Fensterhierarchie
class Label : public Component { };
class Textfield : public Component { };
class Button : public Component {
public:
    int id_; // ID zur Unterscheidung der Buttons
    explicit Button(int id) : id_{id} {}
};
class Window { };
class MyDialog : public Window {
    string title_;
    unique_ptr<Label> lblVorname_{new Label{}};         // lauter Datenfelder
    unique_ptr<Textfield> txtVorname_{new Textfield{}}; // … an die Lebensdauer
    unique_ptr<Label> lblNachname_{new Label{}};        // … der Klasse gebunden
    unique_ptr<Textfield> txtNachname_{new Textfield{}};
    unique_ptr<Button> btnOk_{new Button{1}};
    unique_ptr<Button> btnAbbrechen_{new Button{2}};
public:
    explicit MyDialog(const string& title) : title_{title} {}
    unique_ptr<Button> showModal()
        { return std::move(btnOk_); }    // Platzhaltercode; OK gedrückt
};
unique_ptr<MyDialog> createDialog() {
    return unique_ptr<MyDialog>{ // temporärer Wert
        new MyDialog{"Bitte Namen eingeben"}};
}
int showDialog() {
    unique_ptr<MyDialog> dialog = createDialog();       // lokale Variable
    unique_ptr<Button> gedrueckt = dialog->showModal(); // Rückgabewert
    return gedrueckt->id_;
}
int main() {
    int gedrueckt_id = showDialog();
    if(gedrueckt_id == 1) {
        std::cout << "Danke, dass Sie OK gedrueckt haben\n";
    }
}

Listing 20.6: Ein Spielfeld mit lauter verschiedenen Objekten.

Book listing lst-0520-book.cpp:

// https://godbolt.org/z/sas3b1E3b 
#include <vector>
#include <iostream>
#include <memory>                    // shared_ptr
#include <random>                    // uniform_int_distribution, random_device
namespace {                          // Beginn des anonymen Namensraums
using std::shared_ptr; using std::make_shared;
using std::vector; using std::cout;
struct Asteroid {
    int points_ = 100;
    int structure_ = 10;
};
struct Ship {
    shared_ptr<Asteroid> firedLastOn_{};
    int score_ = 0;
    int firepower = 1;
    bool fireUpon(shared_ptr<Asteroid> a);
};
struct GameBoard {
    vector<shared_ptr<Asteroid>> asteroids_;
    explicit GameBoard(int nAsteroids);
    bool shipFires(Ship& ship);
};
// Implementierung von Ship
bool Ship::fireUpon(shared_ptr<Asteroid> a) {
    if(!a) return false;             // ungültiger Asteroid
    a->structure_ -= firepower;
    if(a.get() == firedLastOn_.get())
        firepower *= 2 ;             // Schaden vergrößern
    else
        firepower = 1;               // zurücksetzen
    firedLastOn_ = a;
    return a->structure_ <= 0;       // kaputt?
}
// Implementierung von GameBoard
GameBoard::GameBoard(int nAsteroids) : asteroids_{}
{   // einige Standard-Asteroiden
    for(int idx=0; idx<nAsteroids; ++idx)
        asteroids_.push_back( make_shared<Asteroid>() );
}
int wuerfel(int min, int max) {
    /* static std::default_random_engine e{}; */   // Pseudozufallsgenerator
    static std::random_device e{};           // Zufallsgenerator
    return std::uniform_int_distribution<int>{min, max}(e); // würfeln
}
bool GameBoard::shipFires(Ship &ship) {
    int idx = wuerfel(0, asteroids_.size()-1);
    bool kaputt = ship.fireUpon(asteroids_[idx]);
    if(kaputt) {
        ship.score_ += asteroids_[idx]->points_;
        asteroids_.erase(asteroids_.begin()+idx);           // entfernen
    }
    return asteroids_.size() == 0;                          // alles kaputt
}
} // Ende des anonymen Namensraums
int main() {
    GameBoard game{10};                                     // 10 Asteroiden
    Ship ship{};
    for(int idx = 0; idx < 85; ++idx) {                     // 85 Schüsse
        if(game.shipFires(ship)) {
            cout << "Der Weltraum ist nach " << idx+1 << " Schuessen leer. ";
            break;
        }
    }
    cout << "Sie haben " << ship.score_ << " Punkte erreicht.\n";
}

Godbolt Listing lst-0520-godb.cpp, https://godbolt.org/z/sas3b1E3b:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sas3b1E3b 
#include <vector>
#include <iostream>
#include <memory>                    // shared_ptr
#include <random>                    // uniform_int_distribution, random_device
namespace {                          // Beginn des anonymen Namensraums
using std::shared_ptr; using std::make_shared;
using std::vector; using std::cout;
struct Asteroid {
    int points_ = 100;
    int structure_ = 10;
};
struct Ship {
    shared_ptr<Asteroid> firedLastOn_{};
    int score_ = 0;
    int firepower = 1;
    bool fireUpon(shared_ptr<Asteroid> a);
};
struct GameBoard {
    vector<shared_ptr<Asteroid>> asteroids_;
    explicit GameBoard(int nAsteroids);
    bool shipFires(Ship& ship);
};
// Implementierung von Ship
bool Ship::fireUpon(shared_ptr<Asteroid> a) {
    if(!a) return false;             // ungültiger Asteroid
    a->structure_ -= firepower;
    if(a.get() == firedLastOn_.get())
        firepower *= 2 ;             // Schaden vergrößern
    else
        firepower = 1;               // zurücksetzen
    firedLastOn_ = a;
    return a->structure_ <= 0;       // kaputt?
}
// Implementierung von GameBoard
GameBoard::GameBoard(int nAsteroids) : asteroids_{}
{   // einige Standard-Asteroiden
    for(int idx=0; idx<nAsteroids; ++idx)
        asteroids_.push_back( make_shared<Asteroid>() );
}
int wuerfel(int min, int max) {
    /* static std::default_random_engine e{}; */   // Pseudozufallsgenerator
    static std::random_device e{};           // Zufallsgenerator
    return std::uniform_int_distribution<int>{min, max}(e); // würfeln
}
bool GameBoard::shipFires(Ship &ship) {
    int idx = wuerfel(0, asteroids_.size()-1);
    bool kaputt = ship.fireUpon(asteroids_[idx]);
    if(kaputt) {
        ship.score_ += asteroids_[idx]->points_;
        asteroids_.erase(asteroids_.begin()+idx);           // entfernen
    }
    return asteroids_.size() == 0;                          // alles kaputt
}
} // Ende des anonymen Namensraums
int main() {
    GameBoard game{10};                                     // 10 Asteroiden
    Ship ship{};
    for(int idx = 0; idx < 85; ++idx) {                     // 85 Schüsse
        if(game.shipFires(ship)) {
            cout << "Der Weltraum ist nach " << idx+1 << " Schuessen leer. ";
            break;
        }
    }
    cout << "Sie haben " << ship.score_ << " Punkte erreicht.\n";
}

Listing 20.7: Wenn ein roher Zeiger ein Objekt besitzt, sind die möglichen Fehler oft schwer zu erkennen.

Book listing lst-0523-book.cpp:

// https://godbolt.org/z/Mqrxxs11Y 
struct StereoImage {
    Image* rechts_;        //             (ERR)  roher Zeiger
    Image* links_;         //             (ERR)  roher Zeiger
    StereoImage(const string& nameBase)           // konstruieren
      : rechts_{new Image{nameBase+"rechts.jpg"}} // okay
      , links_{new Image{nameBase+"links.jpg"}}   // gefährlich
      { }
    ~StereoImage() {       // entfernen
        delete rechts_; delete links_;
    }
    StereoImage(const StereoImage&) = delete;     // keine Kopie
    StereoImage& operator=(const StereoImage&) = delete; // keine Zuweisung
};
int main() {
    Image* bild = new Image{"bild.jpg"};          //             (ERR)  einem rohen Zeiger?
    StereoImage stereo{"3d"};
    delete bild;
}

Godbolt Listing lst-0523-godb.cpp, https://godbolt.org/z/Mqrxxs11Y:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Mqrxxs11Y 
struct StereoImage {
    Image* rechts_;        //             (ERR)  roher Zeiger
    Image* links_;         //             (ERR)  roher Zeiger
    StereoImage(const string& nameBase)           // konstruieren
      : rechts_{new Image{nameBase+"rechts.jpg"}} // okay
      , links_{new Image{nameBase+"links.jpg"}}   // gefährlich
      { }
    ~StereoImage() {       // entfernen
        delete rechts_; delete links_;
    }
    StereoImage(const StereoImage&) = delete;     // keine Kopie
    StereoImage& operator=(const StereoImage&) = delete; // keine Zuweisung
};
int main() {
    Image* bild = new Image{"bild.jpg"};          //             (ERR)  einem rohen Zeiger?
    StereoImage stereo{"3d"};
    delete bild;
}

Listing 20.8: prims enthält Zeiger in einen anderen Container.

Book listing lst-0525-book.cpp:

// https://godbolt.org/z/YMe5PY6aT 
#include <vector>
#include <numeric>   // iota
#include <iostream>
using std::vector; using std::cout;
struct Zahl {        // stellvertretend für ein großes, teures Objekt
    unsigned long val_;
    Zahl(unsigned long val) : val_{val} {}
    Zahl() : val_{0} {}
};
/* ermittelt anhand bisheriger Primzahlen, ob z eine Primzahl ist */
bool isPrim(const Zahl& z, const vector<Zahl*> prims) {
    for(Zahl* p : prims) {
        if((p->val_*p->val_) > z.val_) return true;   // zu groß
        if(z.val_ % p->val_ == 0) return false;       // ist Teiler
    }
    return true;
}
int main() {
    vector<Zahl> alleZahlen(98);   // 98 mit null initialisierte Elemente
    std::iota(begin(alleZahlen), end(alleZahlen), 3); // 3..100
    /* alleZahlen enthält jetzt {3..100} */
    vector<Zahl*> prims{};         // bekommt ermittelte Primzahlen
    Zahl zwei{2};
    prims.push_back(&zwei);        // die 2 wird gebraucht
    for(Zahl &z : alleZahlen) {    // über alle Zahlen iterieren
        if(isPrim(z, prims)) {
            prims.push_back( &z ); // speichere Adresse
        }
    }
    /* Rest ausgeben */
    for(Zahl* p : prims)
        cout << p->val_ << " ";
    cout << "\n";
}

Godbolt Listing lst-0525-godb.cpp, https://godbolt.org/z/YMe5PY6aT:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YMe5PY6aT 
#include <vector>
#include <numeric>   // iota
#include <iostream>
using std::vector; using std::cout;
struct Zahl {        // stellvertretend für ein großes, teures Objekt
    unsigned long val_;
    Zahl(unsigned long val) : val_{val} {}
    Zahl() : val_{0} {}
};
/* ermittelt anhand bisheriger Primzahlen, ob z eine Primzahl ist */
bool isPrim(const Zahl& z, const vector<Zahl*> prims) {
    for(Zahl* p : prims) {
        if((p->val_*p->val_) > z.val_) return true;   // zu groß
        if(z.val_ % p->val_ == 0) return false;       // ist Teiler
    }
    return true;
}
int main() {
    vector<Zahl> alleZahlen(98);   // 98 mit null initialisierte Elemente
    std::iota(begin(alleZahlen), end(alleZahlen), 3); // 3..100
    /* alleZahlen enthält jetzt {3..100} */
    vector<Zahl*> prims{};         // bekommt ermittelte Primzahlen
    Zahl zwei{2};
    prims.push_back(&zwei);        // die 2 wird gebraucht
    for(Zahl &z : alleZahlen) {    // über alle Zahlen iterieren
        if(isPrim(z, prims)) {
            prims.push_back( &z ); // speichere Adresse
        }
    }
    /* Rest ausgeben */
    for(Zahl* p : prims)
        cout << p->val_ << " ";
    cout << "\n";
}

Listing 20.9: Liefern Sie keine Adressen von funktionslokalen Objekten zurück.

Book listing lst-0528-book.cpp:

vector<Zahl*> primZeiger(unsigned long bis) { //             (ERR)  Vektor von Zeigern ist verdächtig
    vector<Zahl> alleZahlen;
    vector<Zahl*> prims{};
    // …
    for(Zahl &z : alleZahlen)
        if(isPrim(z, prims))
            prims.push_back( &z ); // speichere Adresse
    return prims; //             (ERR)  Zeiger auf funktionslokale Objekte
}

Listing 20.10: Mit rohen Zeigern, die in ein C-Array zeigen, können Sie rechnen.

Book listing lst-0533-book.cpp:

// https://godbolt.org/z/3zrK76zn8 
#include <iostream>
int main() {
    int carray[10] = { 1,1 };               // initialisiert zu { 1,1,0,0,0,0,0,0,0,0 }
    int* ende = carray+10;                  // Zeiger hinter das letzte Element
    for(int* p =carray+2; p != ende; ++p) {
        *p = *(p-1) + *(p-2);               // addiert die vorigen beiden Zahlen
    }
    for(int const * p=carray; p != ende; ++p)
        std::cout << *p << " ";
    std::cout << "\n";
}

Godbolt Listing lst-0533-godb.cpp, https://godbolt.org/z/3zrK76zn8:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3zrK76zn8 
#include <iostream>
int main() {
    int carray[10] = { 1,1 };               // initialisiert zu { 1,1,0,0,0,0,0,0,0,0 }
    int* ende = carray+10;                  // Zeiger hinter das letzte Element
    for(int* p =carray+2; p != ende; ++p) {
        *p = *(p-1) + *(p-2);               // addiert die vorigen beiden Zahlen
    }
    for(int const * p=carray; p != ende; ++p)
        std::cout << *p << " ";
    std::cout << "\n";
}

Listing 20.11: C-Arrays verfallen als Parameter zu rohen Zeigern.

Book listing lst-0537-book.cpp:

// https://godbolt.org/z/1qx16Gr61 
#include <iostream>
void fibonacci(int data[], int* ende) {
    for(int* p = data+2; p != ende; ++p) {
        *p = *(p-1) + *(p-2);
    }
}
std::ostream& print(std::ostream &os, int data[], int* ende) {
    for(int const * p=data; p != ende; ++p)
        std::cout << *p << " ";
    return os;
}
int main() {
    int carray[10] = { 1,1 }; // initialisiert zu { 1,1,0,0,0,0,0,0,0,0 }
    fibonacci(carray, carray+10);
    print(std::cout, carray, carray+10) << "\n";
}

Godbolt Listing lst-0537-godb.cpp, https://godbolt.org/z/1qx16Gr61:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1qx16Gr61 
#include <iostream>
void fibonacci(int data[], int* ende) {
    for(int* p = data+2; p != ende; ++p) {
        *p = *(p-1) + *(p-2);
    }
}
std::ostream& print(std::ostream &os, int data[], int* ende) {
    for(int const * p=data; p != ende; ++p)
        std::cout << *p << " ";
    return os;
}
int main() {
    int carray[10] = { 1,1 }; // initialisiert zu { 1,1,0,0,0,0,0,0,0,0 }
    fibonacci(carray, carray+10);
    print(std::cout, carray, carray+10) << "\n";
}

Listing 20.12: »unique_ptr« arbeitet mit dem dynamischen C-Array zusammen.

Book listing lst-0541-book.cpp:

// https://godbolt.org/z/MEqcExjrY 
#include <memory>      // unique_ptr
#include <iostream>    // cout
std::unique_ptr<int[]> createData(size_t sz) {
    return std::unique_ptr<int[]>(new int[sz]);
}
void fibonacci(int data[], int* ende) {
    for(int* p = data+2; p != ende; ++p) {
        *p = *(p-1) + *(p-2);
    }
}
std::ostream& print(std::ostream &os, int data[], int* ende) {
    for(int const* p= data; p != ende; ++p)
        std::cout << *p << " ";
    return os;
}
int main() {
    std::unique_ptr<int[]> data { createData(10) };
    data[0] = 1; // setzen Sie Werte im Array durch den unique_ptr
    data[1] = 1;
    fibonacci(data.get(), data.get()+10); // holen Sie sich den C-Array-Zeiger mit get()
    print(std::cout, data.get(), data.get()+10) << "\n";
}

Godbolt Listing lst-0541-godb.cpp, https://godbolt.org/z/MEqcExjrY:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MEqcExjrY 
#include <memory>      // unique_ptr
#include <iostream>    // cout
std::unique_ptr<int[]> createData(size_t sz) {
    return std::unique_ptr<int[]>(new int[sz]);
}
void fibonacci(int data[], int* ende) {
    for(int* p = data+2; p != ende; ++p) {
        *p = *(p-1) + *(p-2);
    }
}
std::ostream& print(std::ostream &os, int data[], int* ende) {
    for(int const* p= data; p != ende; ++p)
        std::cout << *p << " ";
    return os;
}
int main() {
    std::unique_ptr<int[]> data { createData(10) };
    data[0] = 1; // setzen Sie Werte im Array durch den unique_ptr
    data[1] = 1;
    fibonacci(data.get(), data.get()+10); // holen Sie sich den C-Array-Zeiger mit get()
    print(std::cout, data.get(), data.get()+10) << "\n";
}

GodboltId:s6sss481E

Book listing lst-0545-book.cpp:

// https://godbolt.org/z/s6sss481E 
const char vimes[13] = "Samuel Vimes"; // const char[13]
const char colon[] = "Fred Colon";     // const char[11]
const char* nobby = "Nobby Nobbs";     // const char[12]

Godbolt Listing lst-0545-godb.cpp, https://godbolt.org/z/s6sss481E:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/s6sss481E 
const char vimes[13] = "Samuel Vimes"; // const char[13]
const char colon[] = "Fred Colon";     // const char[11]
const char* nobby = "Nobby Nobbs";     // const char[12]

Listing 20.13: Mit »string« fällt Ihnen oft gar nicht auf, dass Textliterale »const char[]« sind.

Book listing lst-0546-book.cpp:

// https://godbolt.org/z/oKsz7d55T 
#include <string>
#include <iostream>                    // cout
using std::string; using std::cout;
string greet(string name) {
    return name + "!";                 // string operator+(string, const char*)
}
int main() {
    string name{ "Havaloc Vetinari" }; // explizit: string(const char*)
    cout << "Angua";                   // ostream& operator<<(ostream&, const char*)
    cout <<                            // ostream& operator<<(ostream, string)
      greet("Carrot Ironfoundersson"); // implizit: string(const char*)
}

Godbolt Listing lst-0546-godb.cpp, https://godbolt.org/z/oKsz7d55T:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oKsz7d55T 
#include <string>
#include <iostream>                    // cout
using std::string; using std::cout;
string greet(string name) {
    return name + "!";                 // string operator+(string, const char*)
}
int main() {
    string name{ "Havaloc Vetinari" }; // explizit: string(const char*)
    cout << "Angua";                   // ostream& operator<<(ostream&, const char*)
    cout <<                            // ostream& operator<<(ostream, string)
      greet("Carrot Ironfoundersson"); // implizit: string(const char*)
}

Listing 20.14: Iteratoren holen Sie mit »begin« und »end«.

Book listing lst-0547-book.cpp:

// https://godbolt.org/z/4nqz4ed4W 
#include <vector>
#include <iostream> // cout

using std::vector;
int main() {
    vector data{ 5,4,3,2,1 };
    vector<int>::const_iterator ende = data.end(); // oder end(data)
    for(vector<int>::const_iterator it = data.begin(); it!=ende; ++it) {
        std::cout << *it << " ";
    }
    std::cout << "\n";
}

Godbolt Listing lst-0547-godb.cpp, https://godbolt.org/z/4nqz4ed4W:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4nqz4ed4W 
#include <vector>
#include <iostream> // cout

using std::vector;
int main() {
    vector data{ 5,4,3,2,1 };
    vector<int>::const_iterator ende = data.end(); // oder end(data)
    for(vector<int>::const_iterator it = data.begin(); it!=ende; ++it) {
        std::cout << *it << " ";
    }
    std::cout << "\n";
}

Listing 20.15: Rohe Zeiger können Sie wie Iteratoren verwenden.

Book listing lst-0548-book.cpp:

// https://godbolt.org/z/zsqKz76cj 
#include <iostream>   // cout
#include <iterator>   // ostream_iterator
#include <algorithm>  // copy, ranges::copy
int main () {
  int data[6] = { 1, 2, 3, 7, 9, 10 };
  std::ostream_iterator<int> out_it (std::cout,", ");
  std::copy(data, data+6, out_it);           // Zeiger als Iteratoren
  std::cout << "\n";                         // Ausgabe: 1, 2, 3, 7, 9, 10
  std::ranges::copy(data, out_it);           // C-Array-Zeiger als Range
  std::cout << "\n";                         // Ausgabe: 1, 2, 3, 7, 9, 10
}

Godbolt Listing lst-0548-godb.cpp, https://godbolt.org/z/zsqKz76cj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zsqKz76cj 
#include <iostream>   // cout
#include <iterator>   // ostream_iterator
#include <algorithm>  // copy, ranges::copy
int main () {
  int data[6] = { 1, 2, 3, 7, 9, 10 };
  std::ostream_iterator<int> out_it (std::cout,", ");
  std::copy(data, data+6, out_it);           // Zeiger als Iteratoren
  std::cout << "\n";                         // Ausgabe: 1, 2, 3, 7, 9, 10
  std::ranges::copy(data, out_it);           // C-Array-Zeiger als Range
  std::cout << "\n";                         // Ausgabe: 1, 2, 3, 7, 9, 10
}

Listing 20.16: Lohnt es sich, das Freigeben von Speicher zu sparen?

Book listing lst-0549-book.cpp:

// https://godbolt.org/z/M13eYMrjG 
#include <map>
#include <memory> // unique_ptr
#include <string>
#include <iostream>
#include <chrono> // Zeitmessung
using std::map; using std::cout; using std::endl; using namespace std::chrono;
struct Node {
  std::unique_ptr<int> d_;
  Node() : Node{0}  { }
  explicit Node(int d) : d_{ new int } { *d_ = d; } // auch etwas Speicher
  friend bool operator<(const Node& a, const Node& b) {return *a.d_<*b.d_;}
  friend bool operator==(const Node& a, const Node& b) {return *a.d_==*b.d_;}
};
long long millisSeit(steady_clock::time_point start) { // Helfer zur Zeitmessung
  return duration_cast<milliseconds>(steady_clock::now()-start).count();
}

int main() {
  std::unique_ptr<map<int,Node>> riesig{ new map<int,Node>{} };
  cout << "Aufbau..." << endl;
  steady_clock::time_point start = steady_clock::now();
  for(int idx=0; idx < 100*1000*1000; ++idx) {   // massive Menge in der map
      (*riesig)[idx] = Node{idx};
  }
  cout << "Fertig: " << millisSeit(start) << " ms" << endl; // Zeitmessung hier
  start = steady_clock::now();
  riesig.reset();                                           // wegräumen hier
  cout << "Ende: " << millisSeit(start) << " ms" << endl;   // Zeitmessung hier
}

Godbolt Listing lst-0549-godb.cpp, https://godbolt.org/z/M13eYMrjG:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M13eYMrjG 
#include <map>
#include <memory> // unique_ptr
#include <string>
#include <iostream>
#include <chrono> // Zeitmessung
using std::map; using std::cout; using std::endl; using namespace std::chrono;
struct Node {
  std::unique_ptr<int> d_;
  Node() : Node{0}  { }
  explicit Node(int d) : d_{ new int } { *d_ = d; } // auch etwas Speicher
  friend bool operator<(const Node& a, const Node& b) {return *a.d_<*b.d_;}
  friend bool operator==(const Node& a, const Node& b) {return *a.d_==*b.d_;}
};
long long millisSeit(steady_clock::time_point start) { // Helfer zur Zeitmessung
  return duration_cast<milliseconds>(steady_clock::now()-start).count();
}

int main() {
  std::unique_ptr<map<int,Node>> riesig{ new map<int,Node>{} };
  cout << "Aufbau..." << endl;
  steady_clock::time_point start = steady_clock::now();
  for(int idx=0; idx < 100*1000*1000; ++idx) {   // massive Menge in der map
      (*riesig)[idx] = Node{idx};
  }
  cout << "Fertig: " << millisSeit(start) << " ms" << endl; // Zeitmessung hier
  start = steady_clock::now();
  riesig.reset();                                           // wegräumen hier
  cout << "Ende: " << millisSeit(start) << " ms" << endl;   // Zeitmessung hier
}

Listing 21.1: Zeilen, die Präprozessordirektiven enthalten, beginnen mit einem #.

Book listing lst-0551-book.cpp:

// https://godbolt.org/z/MjcvochqP 
// Dateiname: meine-makros.hpp
#ifndef MEINE_MAKROS_HPP  // Include Guard
#define MEINE_MAKROS_HPP
#include <iostream> // cout, cerr
#include <vector>
#ifdef AUSGABE_AUF_STANDARD
#  define OUT std::cout
#else
#  define OUT std::cerr
#endif
#define MESSAGE(text) { (OUT) << text << "\n"; }
using container_type = std::vector<int>;
static constexpr unsigned SIZE = 10;
#endif

Godbolt Listing lst-0551-godb.cpp, https://godbolt.org/z/MjcvochqP:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MjcvochqP 
// Dateiname: meine-makros.hpp
#ifndef MEINE_MAKROS_HPP  // Include Guard
#define MEINE_MAKROS_HPP
#include <iostream> // cout, cerr
#include <vector>
#ifdef AUSGABE_AUF_STANDARD
#  define OUT std::cout
#else
#  define OUT std::cerr
#endif
#define MESSAGE(text) { (OUT) << text << "\n"; }
using container_type = std::vector<int>;
static constexpr unsigned SIZE = 10;
#endif

Listing 21.2: Ihre Hauptdatei mit »main« bindet per »#include« die Headerdatei ein.

Book listing lst-0552-book.cpp:

// https://godbolt.org/z/zG91TMEa8 
// Dateiname: makros.cpp
#define AUSGABE_AUF_STANDARD // Umschalten von cerr und cout
#include "meine-makros.hpp"
#include "meine-makros.hpp"  // Ups, aus Versehen doppelt.
int main() {
    MESSAGE("Programmstart");
    container_type data(SIZE);
    MESSAGE("Der Container hat " << data.size() << " Elemente.");
    MESSAGE("Programmende");
    OUT << "Das ging ja noch mal gut.\n";
}

Godbolt Listing lst-0552-godb.cpp, https://godbolt.org/z/zG91TMEa8:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zG91TMEa8 
// Dateiname: makros.cpp
#define AUSGABE_AUF_STANDARD // Umschalten von cerr und cout
#include "meine-makros.hpp"
#include "meine-makros.hpp"  // Ups, aus Versehen doppelt.
int main() {
    MESSAGE("Programmstart");
    container_type data(SIZE);
    MESSAGE("Der Container hat " << data.size() << " Elemente.");
    MESSAGE("Programmende");
    OUT << "Das ging ja noch mal gut.\n";
}

Listing 21.3: Das Ergebnis des Präprozessordurchlaufs

Book listing lst-0557-book.cpp:

// https://godbolt.org/z/6coqbhfKM 
// …hier Inhalt von <vector>…
// …hier Inhalt von <iostream>…
using container_type = std::vector<int>;
static constexpr unsigned SIZE = 10;
int main() {
  { (std::cout) << "Programmstart" << "\n"; }
  container_type data(SIZE);
  { (std::cout) << "Der Container hat " << data.size() << " Elemente." << "\n";}
  { (std::cout) << "Programmende" << "\n"; }
  { std::cout << "Das ging ja noch mal gut.\n"; }
}

Godbolt Listing lst-0557-godb.cpp, https://godbolt.org/z/6coqbhfKM:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6coqbhfKM 
// …hier Inhalt von <vector>…
// …hier Inhalt von <iostream>…
using container_type = std::vector<int>;
static constexpr unsigned SIZE = 10;
int main() {
  { (std::cout) << "Programmstart" << "\n"; }
  container_type data(SIZE);
  { (std::cout) << "Der Container hat " << data.size() << " Elemente." << "\n";}
  { (std::cout) << "Programmende" << "\n"; }
  { std::cout << "Das ging ja noch mal gut.\n"; }
}

Listing 21.5: Die rein textuelle Ersetzung führt bei Makros zur Mehrfachausführung.

Book listing lst-0565-book.cpp:

// https://godbolt.org/z/jzKfabPh3 
#include <cmath> // sin, cos
constexpr double max2(double a, double b) { return a > b ? a : b; }
#define MAX2(a,b) ((a) > (b) ? (a) : (b))
int main() {
    double f = max2(sin(3.141592/2), cos(3.141592/2));
    double e = MAX2(sin(3.141592/2), cos(3.141592/2));
}

Godbolt Listing lst-0565-godb.cpp, https://godbolt.org/z/jzKfabPh3:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jzKfabPh3 
#include <cmath> // sin, cos
constexpr double max2(double a, double b) { return a > b ? a : b; }
#define MAX2(a,b) ((a) > (b) ? (a) : (b))
int main() {
    double f = max2(sin(3.141592/2), cos(3.141592/2));
    double e = MAX2(sin(3.141592/2), cos(3.141592/2));
}

GodboltId:YzYz3x1zx

Book listing lst-0567-book.cpp:

// https://godbolt.org/z/YzYz3x1zx 
#include <iostream>
#define MAX2(a,b) ((a) > (b) ? (a) : (b))
int main() {
    int x = 0;
    int y = 0;
    int z = MAX2( ++x, ++y ); //             (ERR)  expandiert Argumente mehrfach
    std::cout << "x:"<< x << " y:"<< y << " z:"<<z << '\n';
}

Godbolt Listing lst-0567-godb.cpp, https://godbolt.org/z/YzYz3x1zx:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YzYz3x1zx 
#include <iostream>
#define MAX2(a,b) ((a) > (b) ? (a) : (b))
int main() {
    int x = 0;
    int y = 0;
    int z = MAX2( ++x, ++y ); //             (ERR)  expandiert Argumente mehrfach
    std::cout << "x:"<< x << " y:"<< y << " z:"<<z << '\n';
}

GodboltId:5zrfvovaW

Book listing lst-0568-book.cpp:

// https://godbolt.org/z/5zrfvovaW 
#include <string>
#include <cmath> // sin, cos
#define MAX2(a,b) ((a) > (b) ? (a) : (b))
int main() {
    double e = MAX2(sin(3.141592/2), cos(3.141592/2));
    int i = MAX2(10+12+45, 100/5+20);
    std::string s = MAX2(std::string("Ernie"), std::string("Bert"));
}

Godbolt Listing lst-0568-godb.cpp, https://godbolt.org/z/5zrfvovaW:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5zrfvovaW 
#include <string>
#include <cmath> // sin, cos
#define MAX2(a,b) ((a) > (b) ? (a) : (b))
int main() {
    double e = MAX2(sin(3.141592/2), cos(3.141592/2));
    int i = MAX2(10+12+45, 100/5+20);
    std::string s = MAX2(std::string("Ernie"), std::string("Bert"));
}

GodboltId:6xzTx83zE

Book listing lst-0569-book.cpp:

// https://godbolt.org/z/6xzTx83zE 
#include <string>
#include <cmath> // sin, cos
constexpr double max2(double a, double b) { return  a > b ? a : b; }
constexpr int max2(int a, int b) { return  a > b ? a : b; }
std::string max2(const std::string &a, const std::string &b)
    { return  a > b ? a : b; }
int main() {
    double e = max2(sin(3.141592/2), cos(3.141592/2));
    double i = max2(10+12+45, 100/5+20);
    std::string s = max2("Ernie", "Bert");
}

Godbolt Listing lst-0569-godb.cpp, https://godbolt.org/z/6xzTx83zE:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6xzTx83zE 
#include <string>
#include <cmath> // sin, cos
constexpr double max2(double a, double b) { return  a > b ? a : b; }
constexpr int max2(int a, int b) { return  a > b ? a : b; }
std::string max2(const std::string &a, const std::string &b)
    { return  a > b ? a : b; }
int main() {
    double e = max2(sin(3.141592/2), cos(3.141592/2));
    double i = max2(10+12+45, 100/5+20);
    std::string s = max2("Ernie", "Bert");
}

Listing 21.6: Ein einfaches Funktionstemplate ist viel besser als ein Makro.

Book listing lst-0570-book.cpp:

// https://godbolt.org/z/acMjvxcM5 
#include <string>
#include <cmath> // sin, cos
template<typename TYP>
constexpr TYP max2(const TYP &a, const TYP &b)
    { return  a > b ? a : b; }
int main() {
    double e = max2(sin(3.141592/2), cos(3.141592/2));
    double i = max2(10+12+45, 100/5+20);
    std::string s = max2(std::string("Ernie"), std::string("Bert"));
}

Godbolt Listing lst-0570-godb.cpp, https://godbolt.org/z/acMjvxcM5:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/acMjvxcM5 
#include <string>
#include <cmath> // sin, cos
template<typename TYP>
constexpr TYP max2(const TYP &a, const TYP &b)
    { return  a > b ? a : b; }
int main() {
    double e = max2(sin(3.141592/2), cos(3.141592/2));
    double i = max2(10+12+45, 100/5+20);
    std::string s = max2(std::string("Ernie"), std::string("Bert"));
}

Listing 22.1: Das Programm »gzpack.cpp« nutzt eine C-Bibliothek. Hier sehen Sie die Sektion mit den Includes.

Book listing lst-0577-book.cpp:

// https://godbolt.org/z/9Trh8h8Mb 
#include <string>
#include <vector>
#include <span>      // C++20
#include <fstream>   // ifstream
#include <stdexcept> // runtime_error
#include <iostream>  // cerr
// C-Header:
#include <zlib.h>    // gzXyz; sudo aptitude install libz-dev
#include <cerrno>    // errno
#include <cstring>   // strerror
namespace {
using std::string; using std::span; using std::byte;

Godbolt Listing lst-0577-godb.cpp, https://godbolt.org/z/9Trh8h8Mb:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9Trh8h8Mb 
#include <string>
#include <vector>
#include <span>      // C++20
#include <fstream>   // ifstream
#include <stdexcept> // runtime_error
#include <iostream>  // cerr
// C-Header:
#include <zlib.h>    // gzXyz; sudo aptitude install libz-dev
#include <cerrno>    // errno
#include <cstring>   // strerror
namespace {
using std::string; using std::span; using std::byte;

Listing 22.2: Dieser Teil von »gzpack.cpp« enthält alle verwendeten C-Funktionen.

Book listing lst-0578-book.cpp:

// https://godbolt.org/z/Yh7j1WEGc 
class GzWriteStream {                         // RAII-Wrapper
public:
    gzFile gz_ ;                              // C-Struct aus zlib.h
    explicit GzWriteStream(const string& filename)
        : gz_{gzopen(filename.c_str(),"wb9")} // 'w': write, 'b':binary, '9':level
    {
        if(gz_==NULL) throw std::runtime_error(std::strerror(errno));
    }
    ~GzWriteStream() {
        gzclose(gz_);
    }
    GzWriteStream& operator<<(span<char> &data) {
        write(data);
        return *this;
    }
private:
    void write(span<char> data) {
        auto bytes = std::as_bytes(data); // C++20
        auto res = gzwrite(gz_, bytes.data(), size(bytes));
        if(res==0) throw std::runtime_error("Fehler beim Schreiben");
    }
    GzWriteStream(const GzWriteStream&) = delete;            // keine Kopie
    GzWriteStream& operator=(const GzWriteStream&) = delete; // keine Zuweisung
};

Godbolt Listing lst-0578-godb.cpp, https://godbolt.org/z/Yh7j1WEGc:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Yh7j1WEGc 
class GzWriteStream {                         // RAII-Wrapper
public:
    gzFile gz_ ;                              // C-Struct aus zlib.h
    explicit GzWriteStream(const string& filename)
        : gz_{gzopen(filename.c_str(),"wb9")} // 'w': write, 'b':binary, '9':level
    {
        if(gz_==NULL) throw std::runtime_error(std::strerror(errno));
    }
    ~GzWriteStream() {
        gzclose(gz_);
    }
    GzWriteStream& operator<<(span<char> &data) {
        write(data);
        return *this;
    }
private:
    void write(span<char> data) {
        auto bytes = std::as_bytes(data); // C++20
        auto res = gzwrite(gz_, bytes.data(), size(bytes));
        if(res==0) throw std::runtime_error("Fehler beim Schreiben");
    }
    GzWriteStream(const GzWriteStream&) = delete;            // keine Kopie
    GzWriteStream& operator=(const GzWriteStream&) = delete; // keine Zuweisung
};

Listing 22.3: Dieser Teil von »gzpack.cpp« behandelt das Lesen und Schreiben der Dateien.

Book listing lst-0580-book.cpp:

// https://godbolt.org/z/3P9ToPEYq 
std::vector<char> leseDatei(const string& fName) {
    std::ifstream file{ fName, std::ifstream::binary };
    if(!file) throw std::runtime_error("Fehler beim Oeffnen der Eingabe");
    file.seekg(0, file.end);          // ans Dateiende springen
    const auto laenge = file.tellg(); // aktuelle Position ist Dateigröße
    if(laenge > 1024*1024*1024)
        throw std::runtime_error("Nicht mehr als 1 GB bitte");
    file.seekg(0, file.beg);          // zurück an den Anfang
    std::vector<char> data(laenge);   // Platz schaffen
    file.read(data.data(), laenge);   // in einem Rutsch lesen
    return data;                      // wird nicht kopiert (Stichwort: RVO)
}
void packe(const string& fNameIn, const string& fNameOut) {
    auto data = leseDatei(fNameIn);   // lese Eingabe
    GzWriteStream gz{fNameOut};       // initialisiere Ausgabe
    gz << data;
}

Godbolt Listing lst-0580-godb.cpp, https://godbolt.org/z/3P9ToPEYq:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3P9ToPEYq 
std::vector<char> leseDatei(const string& fName) {
    std::ifstream file{ fName, std::ifstream::binary };
    if(!file) throw std::runtime_error("Fehler beim Oeffnen der Eingabe");
    file.seekg(0, file.end);          // ans Dateiende springen
    const auto laenge = file.tellg(); // aktuelle Position ist Dateigröße
    if(laenge > 1024*1024*1024)
        throw std::runtime_error("Nicht mehr als 1 GB bitte");
    file.seekg(0, file.beg);          // zurück an den Anfang
    std::vector<char> data(laenge);   // Platz schaffen
    file.read(data.data(), laenge);   // in einem Rutsch lesen
    return data;                      // wird nicht kopiert (Stichwort: RVO)
}
void packe(const string& fNameIn, const string& fNameOut) {
    auto data = leseDatei(fNameIn);   // lese Eingabe
    GzWriteStream gz{fNameOut};       // initialisiere Ausgabe
    gz << data;
}

Listing 22.4: Mit »main« des Programms »gzpack.cpp« ist das Beispiel komplett.

Book listing lst-0581-book.cpp:

// https://godbolt.org/z/4sod8vrr6 
} // namespace
int main(int argc, const char* argv[]) {
    try {
        const std::vector<string> fNamen {argv+1, argv+argc};
        for(auto fName : fNamen) {
            std::cout << "packe " << fName << "... ";
            packe(fName, fName+".gz");
            std::cout << fName << ".gz"<< "\n";
        }
    } catch(std::runtime_error &exc) {
        std::cerr << "Fehler: " << exc.what() << "\n";
    }
}

Godbolt Listing lst-0581-godb.cpp, https://godbolt.org/z/4sod8vrr6:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4sod8vrr6 
} // namespace
int main(int argc, const char* argv[]) {
    try {
        const std::vector<string> fNamen {argv+1, argv+argc};
        for(auto fName : fNamen) {
            std::cout << "packe " << fName << "... ";
            packe(fName, fName+".gz");
            std::cout << fName << ".gz"<< "\n";
        }
    } catch(std::runtime_error &exc) {
        std::cerr << "Fehler: " << exc.what() << "\n";
    }
}

Listing 23.1: Der Aufruf eines Funktionstemplates klappt, solange der Funktionskörper mit den Templateparametern gültig ist.

Book listing lst-0591-book.cpp:

// https://godbolt.org/z/aMPj3K7EE 
#include <iostream>
struct Zahl {
    int wert_;
};
template<typename TYP>
void print(TYP value) {
    std::cout << value << "\n";
}
int main() {
    print(5);
    print(-10.25);
    print("Flamingo");
    Zahl sieben { 7 };
    print(sieben); //                                  (ERR)  cout << sieben gibt es nicht
}

Godbolt Listing lst-0591-godb.cpp, https://godbolt.org/z/aMPj3K7EE:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/aMPj3K7EE 
#include <iostream>
struct Zahl {
    int wert_;
};
template<typename TYP>
void print(TYP value) {
    std::cout << value << "\n";
}
int main() {
    print(5);
    print(-10.25);
    print("Flamingo");
    Zahl sieben { 7 };
    print(sieben); //                                  (ERR)  cout << sieben gibt es nicht
}

Listing 23.2: Mit und ohne explizite Typangabe beim Aufruf

Book listing lst-0594-book.cpp:

// https://godbolt.org/z/816Ys17aT 
#include <iostream>
using std::cout;
template<typename TYP>
  void func(TYP a) { cout << a <<" TYP\n"; }
void func(int a) { cout << a << " int\n"; }
int main() {
    func<int>(8); // Ausgabe: 8 TYP
    func(8);      // Ausgabe: 8 int
}

Godbolt Listing lst-0594-godb.cpp, https://godbolt.org/z/816Ys17aT:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/816Ys17aT 
#include <iostream>
using std::cout;
template<typename TYP>
  void func(TYP a) { cout << a <<" TYP\n"; }
void func(int a) { cout << a << " int\n"; }
int main() {
    func<int>(8); // Ausgabe: 8 TYP
    func(8);      // Ausgabe: 8 int
}

Listing 23.3: Ein Templateparameter kann auch eine konstante Zahl sein.

Book listing lst-0596-book.cpp:

// https://godbolt.org/z/c9xzM7EhP 
#include <array>
#include <iostream> // cout
using std::array; using std::cout;
template<size_t SIZE>
array<int,SIZE> createArray() {
    array<int,SIZE> result{};
    return result;
}
int main() {
    auto data = createArray<5>();
    data[3] = 33;
    for(auto e : data) cout << e << " ";
    cout << "\n";
}

Godbolt Listing lst-0596-godb.cpp, https://godbolt.org/z/c9xzM7EhP:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/c9xzM7EhP 
#include <array>
#include <iostream> // cout
using std::array; using std::cout;
template<size_t SIZE>
array<int,SIZE> createArray() {
    array<int,SIZE> result{};
    return result;
}
int main() {
    auto data = createArray<5>();
    data[3] = 33;
    for(auto e : data) cout << e << " ";
    cout << "\n";
}

Listing 23.4: Mit auto als Templateparameter können Sie jeden einfachen Wert angeben.

Book listing lst-0598-book.cpp:

template <auto value> void f() { }
f<10>();               // value bekommt Typ int
f<'a'>();              // value bekommt Typ char

Listing 23.5: Mit »auto« und … können Sie beliebige Werte als Templateparameter angeben.

Book listing lst-0599-book.cpp:

template<auto ... vs> struct GemischteListe {};
using Drei = GemischteListe<'a', 100, 'b'>;
Drei drei{};

Listing 23.6: Für »TYP« wird vom Compiler »const&« ermittelt.

Book listing lst-0601-book.cpp:

// https://godbolt.org/z/cYsTo371z 
#include <iostream>
const int& a_oder_b(int auswahl) {
    static const int a = 42;
    static const int b = 73;
    if(auswahl==1)
        return a; // const& auf innere Variable a zurückgeben
    else
        return b; // const& auf innere Variable b zurückgeben
}
template<typename TYP>
TYP add(TYP a, TYP b) {
    return a + b;
}
int main() {
    auto res = add(
        a_oder_b(0),   // const int&
        a_oder_b(1) ); // const int&
    std::cout << res << "\n"; // Ausgabe: 115
}

Godbolt Listing lst-0601-godb.cpp, https://godbolt.org/z/cYsTo371z:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cYsTo371z 
#include <iostream>
const int& a_oder_b(int auswahl) {
    static const int a = 42;
    static const int b = 73;
    if(auswahl==1)
        return a; // const& auf innere Variable a zurückgeben
    else
        return b; // const& auf innere Variable b zurückgeben
}
template<typename TYP>
TYP add(TYP a, TYP b) {
    return a + b;
}
int main() {
    auto res = add(
        a_oder_b(0),   // const int&
        a_oder_b(1) ); // const int&
    std::cout << res << "\n"; // Ausgabe: 115
}

Listing 23.7: Auch eine Methode kann ein Template sein.

Book listing lst-0603-book.cpp:

// https://godbolt.org/z/bfofn76Ke 
#include <iostream>
class Printer {
    std::ostream& trg_;
public:
    explicit Printer(std::ostream& target)
        : trg_(target)
        {}
    template<typename TYP>
    Printer& print(const TYP& arg) {
        trg_ << arg;
        return *this;
    }
};
int main() {
    Printer normal(std::cout);
    normal.print(7).print(" ").print(3.1415).print("\n");
    Printer fehler(std::cerr);
    fehler.print(8).print(" ").print(2.7183).print("\n");
}

Godbolt Listing lst-0603-godb.cpp, https://godbolt.org/z/bfofn76Ke:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bfofn76Ke 
#include <iostream>
class Printer {
    std::ostream& trg_;
public:
    explicit Printer(std::ostream& target)
        : trg_(target)
        {}
    template<typename TYP>
    Printer& print(const TYP& arg) {
        trg_ << arg;
        return *this;
    }
};
int main() {
    Printer normal(std::cout);
    normal.print(7).print(" ").print(3.1415).print("\n");
    Printer fehler(std::cerr);
    fehler.print(8).print(" ").print(2.7183).print("\n");
}

Listing 23.8: Auch in der Standardbibliothek finden Sie allerlei Funktionstemplates.

Book listing lst-0604-book.cpp:

// https://godbolt.org/z/oTn1K4sGG 
#include <vector>
#include <iostream>  // cout, ostream
#include <algorithm> // sort, copy
#include <iterator>  // ostream_iterator
int main() {
    std::ostream_iterator<int> oit(std::cout," ");
    std::vector data { 100, 50, 1, 75, 25, 0 };       // vector<int>
    std::sort(std::begin(data), std::end(data));      // Iteratorenpaar
    std::copy(std::begin(data), std::end(data), oit); // Iteratorenpaar
    std::cout << '\n';                                // Ausgabe: 0 1 25 50 75 100
    std::ranges::reverse(data);                       // Range
    std::ranges::copy(data, oit);                     // Range
    std::cout << '\n';                                // Ausgabe: 100 75 50 25 1 0
}

Godbolt Listing lst-0604-godb.cpp, https://godbolt.org/z/oTn1K4sGG:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oTn1K4sGG 
#include <vector>
#include <iostream>  // cout, ostream
#include <algorithm> // sort, copy
#include <iterator>  // ostream_iterator
int main() {
    std::ostream_iterator<int> oit(std::cout," ");
    std::vector data { 100, 50, 1, 75, 25, 0 };       // vector<int>
    std::sort(std::begin(data), std::end(data));      // Iteratorenpaar
    std::copy(std::begin(data), std::end(data), oit); // Iteratorenpaar
    std::cout << '\n';                                // Ausgabe: 0 1 25 50 75 100
    std::ranges::reverse(data);                       // Range
    std::ranges::copy(data, oit);                     // Range
    std::cout << '\n';                                // Ausgabe: 100 75 50 25 1 0
}

Listing 23.9: Eigenen Algorithmen übergeben Sie Ranges als Argumente, nicht den Container.

Book listing lst-0605-book.cpp:

// https://godbolt.org/z/h3baE65od 
#include <iostream>
#include <vector>
#include <set>
#include <bitset>
#include <ranges>
namespace rng = std::ranges;
std::ostream& druckeBinaer(std::ostream& os, rng::input_range auto&& range) {
    for(auto&& elem : range) {
        std::bitset<4> x(elem); // Zahl in bitset kopieren
        os << x << " ";
    }
    return os;
}
int main()
{
    std::vector vdata { 2, 0, 15, 12 };
    druckeBinaer(std::cout, vdata) << "\n";
    // Ausgabe: 0010 0000 1111 1100
    std::set sdata { 2, 0, 12, 15 };
    druckeBinaer(std::cout, sdata) << "\n";
    // Ausgabe: 0000 0010 1100 1111
    int adata[] = { 0,1,2,13,14,15 };
    druckeBinaer(std::cout, adata) << "\n";
    // Ausgabe: 0000 0001 0010 1101 1110 1111
}

Godbolt Listing lst-0605-godb.cpp, https://godbolt.org/z/h3baE65od:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h3baE65od 
#include <iostream>
#include <vector>
#include <set>
#include <bitset>
#include <ranges>
namespace rng = std::ranges;
std::ostream& druckeBinaer(std::ostream& os, rng::input_range auto&& range) {
    for(auto&& elem : range) {
        std::bitset<4> x(elem); // Zahl in bitset kopieren
        os << x << " ";
    }
    return os;
}
int main()
{
    std::vector vdata { 2, 0, 15, 12 };
    druckeBinaer(std::cout, vdata) << "\n";
    // Ausgabe: 0010 0000 1111 1100
    std::set sdata { 2, 0, 12, 15 };
    druckeBinaer(std::cout, sdata) << "\n";
    // Ausgabe: 0000 0010 1100 1111
    int adata[] = { 0,1,2,13,14,15 };
    druckeBinaer(std::cout, adata) << "\n";
    // Ausgabe: 0000 0001 0010 1101 1110 1111
}

Listing 23.10: Eigenen Algorithmen übergeben Sie Iteratoren als Argumente, nicht den Container.

Book listing lst-0606-book.cpp:

// https://godbolt.org/z/13eMxKTfj 
#include <iostream>
#include <vector>
#include <set>
#include <bitset>
template<typename IT>
std::ostream& druckeBinaer(std::ostream& os, IT begin, IT end)
{
    for(IT it=begin; it != end; ++it) {
        std::bitset<4> x(*it); // Zahl in bitset kopieren
        os << x << " ";
    }
    return os;
}
int main()
{
    std::vector<int> vdata { 2, 0, 15, 12 };
    druckeBinaer(std::cout, vdata.cbegin(), vdata.cend()) << "\n";
    // Ausgabe: 0010 0000 1111 1100
    std::set<int> sdata { 2, 0, 12, 15 };
    druckeBinaer(std::cout, std::begin(sdata), std::end(sdata)) << "\n";
    // Ausgabe: 0000 0010 1100 1111
    int adata[] = { 0,1,2,13,14,15 };
    druckeBinaer(std::cout, std::begin(adata), std::end(adata)) << "\n";
    // Ausgabe: 0000 0001 0010 1101 1110 1111
}

Godbolt Listing lst-0606-godb.cpp, https://godbolt.org/z/13eMxKTfj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/13eMxKTfj 
#include <iostream>
#include <vector>
#include <set>
#include <bitset>
template<typename IT>
std::ostream& druckeBinaer(std::ostream& os, IT begin, IT end)
{
    for(IT it=begin; it != end; ++it) {
        std::bitset<4> x(*it); // Zahl in bitset kopieren
        os << x << " ";
    }
    return os;
}
int main()
{
    std::vector<int> vdata { 2, 0, 15, 12 };
    druckeBinaer(std::cout, vdata.cbegin(), vdata.cend()) << "\n";
    // Ausgabe: 0010 0000 1111 1100
    std::set<int> sdata { 2, 0, 12, 15 };
    druckeBinaer(std::cout, std::begin(sdata), std::end(sdata)) << "\n";
    // Ausgabe: 0000 0010 1100 1111
    int adata[] = { 0,1,2,13,14,15 };
    druckeBinaer(std::cout, std::begin(adata), std::end(adata)) << "\n";
    // Ausgabe: 0000 0001 0010 1101 1110 1111
}

Listing 23.11: So finden Sie den Zahlenbereich der Ganzzahltypen heraus.

Book listing lst-0608-book.cpp:

// https://godbolt.org/z/oY9v9a8d6 
#include <iostream>                                  // cout
#include <limits>                                    // numeric_limits
template<typename INT_TYP>                           // Template mit Typargument
void infos(const char* name) {
    using L = typename std::numeric_limits<INT_TYP>; // kürzer umbenennen
    std::cout
        << name
        << " zahlenbits:" << L::digits               // Bits ohne Vorzeichenbit
        << " vorzeichen:" << L::is_signed            // speichert Vorzeichen?
        << " min:"<< (long long)L::min()             // kleinster möglicher Wert
        << " max:"<< (long long)L::max()             // größter möglicher Wert
        << "\n";
}
int main() {
    infos<signed char>("char");                      // kleinster int-Typ
    infos<short>("short");
    infos<int>("int");
    infos<long>("long");
    infos<long long>("long long");                   // größter int-Typ
}

Godbolt Listing lst-0608-godb.cpp, https://godbolt.org/z/oY9v9a8d6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oY9v9a8d6 
#include <iostream>                                  // cout
#include <limits>                                    // numeric_limits
template<typename INT_TYP>                           // Template mit Typargument
void infos(const char* name) {
    using L = typename std::numeric_limits<INT_TYP>; // kürzer umbenennen
    std::cout
        << name
        << " zahlenbits:" << L::digits               // Bits ohne Vorzeichenbit
        << " vorzeichen:" << L::is_signed            // speichert Vorzeichen?
        << " min:"<< (long long)L::min()             // kleinster möglicher Wert
        << " max:"<< (long long)L::max()             // größter möglicher Wert
        << "\n";
}
int main() {
    infos<signed char>("char");                      // kleinster int-Typ
    infos<short>("short");
    infos<int>("int");
    infos<long>("long");
    infos<long long>("long long");                   // größter int-Typ
}

Listing 23.12: Eine Funktion als Parameter

Book listing lst-0609-book.cpp:

#include <functional> // function
int berechne(int a, int b, std::function<int(int,int)> binop) {
    return binop(a,b);
}

Listing 23.13: Verwenden Sie den Namen einer passenden Funktion als Funktionsparameter.

Book listing lst-0612-book.cpp:

// https://godbolt.org/z/7YKjcTbhn 
#include <functional> // function
#include <iostream>   // cout
int berechne(int a, int b, std::function<int(int,int)> binop) {
    return binop(a,b);
}
int plus(int a, int b) { return a+b; }
int mal(int a, int b) { return a*b; }
int main() {
    std::cout << berechne(3, 4, plus) << "\n"; // Ausgabe: 7
    std::cout << berechne(3, 4, mal) << "\n";  // Ausgabe: 12
}

Godbolt Listing lst-0612-godb.cpp, https://godbolt.org/z/7YKjcTbhn:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7YKjcTbhn 
#include <functional> // function
#include <iostream>   // cout
int berechne(int a, int b, std::function<int(int,int)> binop) {
    return binop(a,b);
}
int plus(int a, int b) { return a+b; }
int mal(int a, int b) { return a*b; }
int main() {
    std::cout << berechne(3, 4, plus) << "\n"; // Ausgabe: 7
    std::cout << berechne(3, 4, mal) << "\n";  // Ausgabe: 12
}

Listing 23.14: Es ist egal, ob Sie beim Aufruf den Adressoperator verwenden oder nicht.

Book listing lst-0615-book.cpp:

// https://godbolt.org/z/WbnThTs8e 
#include <functional> // function
#include <iostream>   // cout
int berechne(int a, int b, std::function<int(int,int)> binop) {
    return binop(a,b);
}
int plus(int a, int b) { return a+b; }
int mal(int a, int b) { return a*b; }
int main() {
    std::cout << berechne(3, 4, plus) << "\n";  // Wert-Schreibweise
    std::cout << berechne(3, 4, mal) << "\n";   // Wert-Schreibweise
    std::cout << berechne(3, 4, &plus) << "\n"; // Zeiger-Schreibweise
    std::cout << berechne(3, 4, &mal) << "\n";  // Zeiger-Schreibweise
}

Godbolt Listing lst-0615-godb.cpp, https://godbolt.org/z/WbnThTs8e:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WbnThTs8e 
#include <functional> // function
#include <iostream>   // cout
int berechne(int a, int b, std::function<int(int,int)> binop) {
    return binop(a,b);
}
int plus(int a, int b) { return a+b; }
int mal(int a, int b) { return a*b; }
int main() {
    std::cout << berechne(3, 4, plus) << "\n";  // Wert-Schreibweise
    std::cout << berechne(3, 4, mal) << "\n";   // Wert-Schreibweise
    std::cout << berechne(3, 4, &plus) << "\n"; // Zeiger-Schreibweise
    std::cout << berechne(3, 4, &mal) << "\n";  // Zeiger-Schreibweise
}

Listing 23.15: Eine Klasse mit »operator()« erzeugt Funktionsobjekte.

Book listing lst-0616-book.cpp:

// https://godbolt.org/z/Px83WPKfq 
#include <iostream>                      // cout
using std::cout;
class Inkrement {
   int menge_;
public:
    explicit Inkrement(int menge) : menge_{menge} {}
    int operator()(int wert) const  {    // macht Instanzen aufrufbar
        return wert + menge_;
    }
    void clear() {
        menge_ = 0;
    }
};
int main() {
    Inkrement plusVier{4};               // Instanz erzeugen
    Inkrement plusElf{11};               // noch eine Instanz
    cout << plusVier(8) << "\n";         // Ausgabe: 12
    int erg = 2 * plusElf(5) - 7;        // erg ist 25
    cout << plusElf(erg/5) << "\n";      // Ausgabe: 16
    cout << 3 * Inkrement{1}(7) << "\n"; // Ausgabe: 24
    Inkrement plusNix = plusElf;
    plusNix.clear();                     // Zustand ändern
    cout << plusNix(1) << "\n";          // Ausgabe: 1
}

Godbolt Listing lst-0616-godb.cpp, https://godbolt.org/z/Px83WPKfq:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Px83WPKfq 
#include <iostream>                      // cout
using std::cout;
class Inkrement {
   int menge_;
public:
    explicit Inkrement(int menge) : menge_{menge} {}
    int operator()(int wert) const  {    // macht Instanzen aufrufbar
        return wert + menge_;
    }
    void clear() {
        menge_ = 0;
    }
};
int main() {
    Inkrement plusVier{4};               // Instanz erzeugen
    Inkrement plusElf{11};               // noch eine Instanz
    cout << plusVier(8) << "\n";         // Ausgabe: 12
    int erg = 2 * plusElf(5) - 7;        // erg ist 25
    cout << plusElf(erg/5) << "\n";      // Ausgabe: 16
    cout << 3 * Inkrement{1}(7) << "\n"; // Ausgabe: 24
    Inkrement plusNix = plusElf;
    plusNix.clear();                     // Zustand ändern
    cout << plusNix(1) << "\n";          // Ausgabe: 1
}

Listing 23.16: Eine Klasse mit einer normalen Methode

Book listing lst-0619-book.cpp:

// https://godbolt.org/z/EExfde3vP 
#include <iostream>              // cout
using std::cout;

class Hinzu {
   int menge_;
public:
    explicit Hinzu(int menge) : menge_{menge} {}
    int hinzu(int wert) const  {            // statt operator()
        return wert + menge_;
    }
    void clear() {
        menge_ = 0;
    }
};
int main() {
    Hinzu plusVier{4};                      // Instanz erzeugen
    Hinzu plusElf{11};                      // noch eine Instanz
    cout << plusVier.hinzu(8) << "\n";      // Ausgabe: 12
    int erg = 2 * plusElf.hinzu(5) - 7;     // erg ist 25
    cout << plusElf.hinzu(erg/5) << "\n";   // Ausgabe: 16
    cout << 3 * Hinzu{1}.hinzu(7) << "\n";  // Ausgabe: 24
    Hinzu plusNix = plusElf;
    plusNix.clear();                        // Zustand ändern
    cout << plusNix.hinzu(1) << "\n";       // Ausgabe: 1
}

Godbolt Listing lst-0619-godb.cpp, https://godbolt.org/z/EExfde3vP:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/EExfde3vP 
#include <iostream>              // cout
using std::cout;

class Hinzu {
   int menge_;
public:
    explicit Hinzu(int menge) : menge_{menge} {}
    int hinzu(int wert) const  {            // statt operator()
        return wert + menge_;
    }
    void clear() {
        menge_ = 0;
    }
};
int main() {
    Hinzu plusVier{4};                      // Instanz erzeugen
    Hinzu plusElf{11};                      // noch eine Instanz
    cout << plusVier.hinzu(8) << "\n";      // Ausgabe: 12
    int erg = 2 * plusElf.hinzu(5) - 7;     // erg ist 25
    cout << plusElf.hinzu(erg/5) << "\n";   // Ausgabe: 16
    cout << 3 * Hinzu{1}.hinzu(7) << "\n";  // Ausgabe: 24
    Hinzu plusNix = plusElf;
    plusNix.clear();                        // Zustand ändern
    cout << plusNix.hinzu(1) << "\n";       // Ausgabe: 1
}

Listing 23.17: Mit »operator<« als Funktion können Sie nur eine Sortierung implementieren.

Book listing lst-0620-book.cpp:

// https://godbolt.org/z/3ch51ov87 
#include <set>
#include <string>
#include <iostream> // cout
using std::string; using std::set; using std::cout;
struct Zwerg {
    string name_;
    unsigned jahr_;
};
bool operator<(const Zwerg& a, const Zwerg& b) {
    return a.name_ < b.name_;
}
int main() {
    set zwerge{ Zwerg{"Balin", 2763}, Zwerg{"Dwalin", 2772},
        Zwerg{"Oin", 2774}, Zwerg{"Gloin", 2783}, Zwerg{"Thorin", 2746},
        Zwerg{"Fili", 2859}, Zwerg{"Kili", 2864} };
    for(const auto& z : zwerge) // sortierte Ausgabe: "Balin" bis "Thorin"
        cout << z.name_  << " ";
    cout << "\n";
}

Godbolt Listing lst-0620-godb.cpp, https://godbolt.org/z/3ch51ov87:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3ch51ov87 
#include <set>
#include <string>
#include <iostream> // cout
using std::string; using std::set; using std::cout;
struct Zwerg {
    string name_;
    unsigned jahr_;
};
bool operator<(const Zwerg& a, const Zwerg& b) {
    return a.name_ < b.name_;
}
int main() {
    set zwerge{ Zwerg{"Balin", 2763}, Zwerg{"Dwalin", 2772},
        Zwerg{"Oin", 2774}, Zwerg{"Gloin", 2783}, Zwerg{"Thorin", 2746},
        Zwerg{"Fili", 2859}, Zwerg{"Kili", 2864} };
    for(const auto& z : zwerge) // sortierte Ausgabe: "Balin" bis "Thorin"
        cout << z.name_  << " ";
    cout << "\n";
}

Listing 23.18: Ein Funktor ohne Schnickschnack, aber mit großem Nutzen

Book listing lst-0622-book.cpp:

struct NachJahr { // implementiert less-than nach Zwerg::jahr_
    bool operator()(const Zwerg& a, const Zwerg& b) const {
        return a.jahr_ < b.jahr_;
    }
};

GodboltId:53EcTMo3e

Book listing lst-0623-book.cpp:

// https://godbolt.org/z/53EcTMo3e 
set<Zwerg,NachJahr> zwerge2{begin(zwerge), end(zwerge)};
for(const auto& z : zwerge2) // anders sortierte Ausgabe
    cout << z.jahr_ << " ";

Godbolt Listing lst-0623-godb.cpp, https://godbolt.org/z/53EcTMo3e:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/53EcTMo3e 
set<Zwerg,NachJahr> zwerge2{begin(zwerge), end(zwerge)};
for(const auto& z : zwerge2) // anders sortierte Ausgabe
    cout << z.jahr_ << " ";

Listing 23.19: Viele Algorithmen der Standardbibliothek arbeiten ebenfalls mit »operator<«.

Book listing lst-0627-book.cpp:

// https://godbolt.org/z/MrcGhxTdT 
#include <vector>
#include <algorithm>  // sort
// Definitionen und weitere Includes wie zuvor
int main() {
    vector zwerge{    // initialisieren wie zuvor
    /* sortieren */
    std::sort(begin(zwerge), end(zwerge));
    // ausgeben wie zuvor …

Godbolt Listing lst-0627-godb.cpp, https://godbolt.org/z/MrcGhxTdT:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MrcGhxTdT 
#include <vector>
#include <algorithm>  // sort
// Definitionen und weitere Includes wie zuvor
int main() {
    vector zwerge{    // initialisieren wie zuvor
    /* sortieren */
    std::sort(begin(zwerge), end(zwerge));
    // ausgeben wie zuvor …

Listing 23.20: Mit der Zugriffsklausel können Sie im Lambda auf äußere Variablen zugreifen.

Book listing lst-0634-book.cpp:

// https://godbolt.org/z/ers9eWPbG 
#include <vector>
#include <string>
#include <algorithm> // sort
#include <iostream>  // cout
using std::string; using std::vector; using std::cout;
// wie zuvor
int main() {
    vector zwerge{    // wie zuvor
    /* sortieren */
    bool rueckwaerts = true; // oder false. Variable außerhalb des Lambdas
    std::ranges::sort(zwerge,
        [rueckwaerts](const Zwerg& a, const Zwerg& b) {
            if(rueckwaerts)
                return a.name_ > b.name_;
            else
                return a.name_ < b.name_;
        }
    );
    /* ausgeben */
    for(const auto& z : zwerge) // rückwärts: "Thorin" bis "Balin"
        cout << z.name_  << " ";
    cout << "\n";
}

Godbolt Listing lst-0634-godb.cpp, https://godbolt.org/z/ers9eWPbG:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ers9eWPbG 
#include <vector>
#include <string>
#include <algorithm> // sort
#include <iostream>  // cout
using std::string; using std::vector; using std::cout;
// wie zuvor
int main() {
    vector zwerge{    // wie zuvor
    /* sortieren */
    bool rueckwaerts = true; // oder false. Variable außerhalb des Lambdas
    std::ranges::sort(zwerge,
        [rueckwaerts](const Zwerg& a, const Zwerg& b) {
            if(rueckwaerts)
                return a.name_ > b.name_;
            else
                return a.name_ < b.name_;
        }
    );
    /* ausgeben */
    for(const auto& z : zwerge) // rückwärts: "Thorin" bis "Balin"
        cout << z.name_  << " ";
    cout << "\n";
}

Listing 23.21: Die Zugriffsklausel kann auch Referenzen enthalten.

Book listing lst-0635-book.cpp:

// https://godbolt.org/z/4zYsWW9Wq 
#include <vector>
#include <string>
#include <algorithm> // sort
#include <iostream>  // cout
using std::string; using std::vector; using std::cout;
// wie zuvor
int main() {
    vector zwerge{           // wie zuvor
    /* sortieren */
    bool rueckwaerts = true; // oder false. Variable außerhalb des Lambdas
    unsigned richtigrum = 0; // zählt < mit
    unsigned falschrum = 0;  // zählt > mit
    std::ranges::sort(zwerge,
        [rueckwaerts,&falschrum,&richtigrum](const Zwerg& a, const Zwerg& b) {
            bool result = rueckwaerts
                ? a.name_ > b.name_
                : a.name_ < b.name_;
            if(result==false) ++falschrum; else ++richtigrum;
            return result;
        }
    );
    /* ausgeben */
    cout << "Falschrum:" << falschrum << " Richtigrum: " << richtigrum << "\n";
    for(const auto& z : zwerge) // rückwärts: "Thorin" bis "Balin"
        cout << z.name_  << " ";
    cout << "\n";
}

Godbolt Listing lst-0635-godb.cpp, https://godbolt.org/z/4zYsWW9Wq:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4zYsWW9Wq 
#include <vector>
#include <string>
#include <algorithm> // sort
#include <iostream>  // cout
using std::string; using std::vector; using std::cout;
// wie zuvor
int main() {
    vector zwerge{           // wie zuvor
    /* sortieren */
    bool rueckwaerts = true; // oder false. Variable außerhalb des Lambdas
    unsigned richtigrum = 0; // zählt < mit
    unsigned falschrum = 0;  // zählt > mit
    std::ranges::sort(zwerge,
        [rueckwaerts,&falschrum,&richtigrum](const Zwerg& a, const Zwerg& b) {
            bool result = rueckwaerts
                ? a.name_ > b.name_
                : a.name_ < b.name_;
            if(result==false) ++falschrum; else ++richtigrum;
            return result;
        }
    );
    /* ausgeben */
    cout << "Falschrum:" << falschrum << " Richtigrum: " << richtigrum << "\n";
    for(const auto& z : zwerge) // rückwärts: "Thorin" bis "Balin"
        cout << z.name_  << " ";
    cout << "\n";
}

Listing 23.22: »mutable« macht Wert-Captures in Lambdas veränderbar.

Book listing lst-0637-book.cpp:

// https://godbolt.org/z/zMWo69974 
#include <iostream>
int main() {
    int count = 0;
    auto plus1 = [count](int x) mutable { // count als Kopie
        std::cout << ++count; return x+1;
    };
    for(int i=0; i<5; ++i) {
        plus1(i);
    }
    std::cout << "\n";
    // Ausgabe: 12345
}

Godbolt Listing lst-0637-godb.cpp, https://godbolt.org/z/zMWo69974:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zMWo69974 
#include <iostream>
int main() {
    int count = 0;
    auto plus1 = [count](int x) mutable { // count als Kopie
        std::cout << ++count; return x+1;
    };
    for(int i=0; i<5; ++i) {
        plus1(i);
    }
    std::cout << "\n";
    // Ausgabe: 12345
}

Listing 23.23: Wenn möglich, besser ohne mutable

Book listing lst-0638-book.cpp:

// https://godbolt.org/z/8GxPMEc5o 
#include <iostream>
int main() {
    int count = 0;
    auto plus1 = [&count](int x) { // count als Referenz
        ++count; return x+1;
    };
    for(int i=0; i<5; ++i) { plus1(i); }
    std::cout << "plus1 wurde " << count << " Mal aufgerufen\n";
    // Ausgabe: plus1 wurde 5 Mal aufgerufen
}

Godbolt Listing lst-0638-godb.cpp, https://godbolt.org/z/8GxPMEc5o:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8GxPMEc5o 
#include <iostream>
int main() {
    int count = 0;
    auto plus1 = [&count](int x) { // count als Referenz
        ++count; return x+1;
    };
    for(int i=0; i<5; ++i) { plus1(i); }
    std::cout << "plus1 wurde " << count << " Mal aufgerufen\n";
    // Ausgabe: plus1 wurde 5 Mal aufgerufen
}

GodboltId:YWe15Ehd8

Book listing lst-0641-book.cpp:

// https://godbolt.org/z/YWe15Ehd8 
#include <iostream>
#include <string>
using std::cout; using std::string; using namespace std::literals;
auto min2 = [](const auto &a, const auto &b) {
    return a<b ? a : b;
};
auto min3 = [](const auto &a, const auto &b, const auto &c) {
    return min2(a, min2(b,c));
};
int main() {
    cout << min3( 3, 7, 2 ) << '\n';                  // Ausgabe: 2
    cout << min3( 8.11, 113.2, -3.1 ) << '\n';        // Ausgabe: –3.1
    cout << min3( "Zoo"s, "Affe"s, "Muli"s ) << '\n'; // Ausgabe: Affe
}

Godbolt Listing lst-0641-godb.cpp, https://godbolt.org/z/YWe15Ehd8:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YWe15Ehd8 
#include <iostream>
#include <string>
using std::cout; using std::string; using namespace std::literals;
auto min2 = [](const auto &a, const auto &b) {
    return a<b ? a : b;
};
auto min3 = [](const auto &a, const auto &b, const auto &c) {
    return min2(a, min2(b,c));
};
int main() {
    cout << min3( 3, 7, 2 ) << '\n';                  // Ausgabe: 2
    cout << min3( 8.11, 113.2, -3.1 ) << '\n';        // Ausgabe: –3.1
    cout << min3( "Zoo"s, "Affe"s, "Muli"s ) << '\n'; // Ausgabe: Affe
}

GodboltId:nenW8aM81

Book listing lst-0642-book.cpp:

// https://godbolt.org/z/nenW8aM81 
auto min2 = []<typename T>(const T &a, const T &b) {
    return a<b ? a : b;
};
auto min3 = []<typename T>(const T &a, const T &b, const T &c) {
    return min2(a, min2(b,c));
};

Godbolt Listing lst-0642-godb.cpp, https://godbolt.org/z/nenW8aM81:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/nenW8aM81 
auto min2 = []<typename T>(const T &a, const T &b) {
    return a<b ? a : b;
};
auto min3 = []<typename T>(const T &a, const T &b, const T &c) {
    return min2(a, min2(b,c));
};

Listing 23.24: Concepts können auf unterschiedliche Weise geschrieben werden.

Book listing lst-0643-book.cpp:

// https://godbolt.org/z/W6cdra8K9 
#include <concepts>  // integral
#include <iostream>
using namespace std;
// Concept explizit mit requires
template<typename T> requires integral<T>
auto add_1(T val) { return val+1; }
// abgekürztes Concept
template<integral T>
auto add_2(T val) { return val+2; }
// abgekürztes Funktionstemplate mit Concept
auto add_3(integral auto val) { return val+3; }
// Ad-hoc-requires für Funktionstemplate
auto add_4(auto val) requires integral<decltype(val)>
{ return val+4; }
int main() {
  cout << add_1(1) << '\n';              // Ausgabe: 2
  cout << add_2(1) << '\n';              // Ausgabe: 3
  cout << add_3(1) << '\n';              // Ausgabe: 4
  cout << add_4(1) << '\n';              // Ausgabe: 5
  cout << add_3("text") << '\n';         //                                  (ERR)  Fehler
  integral auto val = add_1(99);         // auch für auto-Variablen
  cout << val << '\n';                   // Ausgabe: 100
}

Godbolt Listing lst-0643-godb.cpp, https://godbolt.org/z/W6cdra8K9:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/W6cdra8K9 
#include <concepts>  // integral
#include <iostream>
using namespace std;
// Concept explizit mit requires
template<typename T> requires integral<T>
auto add_1(T val) { return val+1; }
// abgekürztes Concept
template<integral T>
auto add_2(T val) { return val+2; }
// abgekürztes Funktionstemplate mit Concept
auto add_3(integral auto val) { return val+3; }
// Ad-hoc-requires für Funktionstemplate
auto add_4(auto val) requires integral<decltype(val)>
{ return val+4; }
int main() {
  cout << add_1(1) << '\n';              // Ausgabe: 2
  cout << add_2(1) << '\n';              // Ausgabe: 3
  cout << add_3(1) << '\n';              // Ausgabe: 4
  cout << add_4(1) << '\n';              // Ausgabe: 5
  cout << add_3("text") << '\n';         //                                  (ERR)  Fehler
  integral auto val = add_1(99);         // auch für auto-Variablen
  cout << val << '\n';                   // Ausgabe: 100
}

Listing 23.25: Mit Concepts können Sie einzelne Überladungen einschränken.

Book listing lst-0644-book.cpp:

// https://godbolt.org/z/Kxrz5ETh6 
#include <concepts>  // integral, floating_point
#include <iostream>
using namespace std;
int64_t trunc_to_10(integral auto val) { return (val/10)*10; }
int64_t trunc_to_10(floating_point auto val) { return int64_t(val/10)*10; }
int main() {
  cout << trunc_to_10(144) << '\n';    // Ausgabe: 140
  cout << trunc_to_10(122.2) << '\n';  // Ausgabe: 120
}

Godbolt Listing lst-0644-godb.cpp, https://godbolt.org/z/Kxrz5ETh6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Kxrz5ETh6 
#include <concepts>  // integral, floating_point
#include <iostream>
using namespace std;
int64_t trunc_to_10(integral auto val) { return (val/10)*10; }
int64_t trunc_to_10(floating_point auto val) { return int64_t(val/10)*10; }
int main() {
  cout << trunc_to_10(144) << '\n';    // Ausgabe: 140
  cout << trunc_to_10(122.2) << '\n';  // Ausgabe: 120
}

GodboltId:eaGre4bqr

Book listing lst-0646-book.cpp:

// https://godbolt.org/z/eaGre4bqr 
auto min2(const std::integral auto &a, const std::integral auto &b) {
    return a<b ? a : b;
};

auto min3 = []<std::integral T>(const T &a, const T &b, const T &c) {
    return min2(a, min2(b,c));
};

int main() {
    cout << min3( 3, 7, 2 ) << '\n';
    cout << min3( 8.11, 113.2, -3.1 ) << '\n'; //                                  (ERR)  Fehler: kein integraler Typ

Godbolt Listing lst-0646-godb.cpp, https://godbolt.org/z/eaGre4bqr:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eaGre4bqr 
auto min2(const std::integral auto &a, const std::integral auto &b) {
    return a<b ? a : b;
};

auto min3 = []<std::integral T>(const T &a, const T &b, const T &c) {
    return min2(a, min2(b,c));
};

int main() {
    cout << min3( 3, 7, 2 ) << '\n';
    cout << min3( 8.11, 113.2, -3.1 ) << '\n'; //                                  (ERR)  Fehler: kein integraler Typ

Listing 23.26: Geben Sie weitere Bedingungen mit requires an.

Book listing lst-0647-book.cpp:

// https://godbolt.org/z/orTK9daa3 
#include <concepts>
#include <iostream>
#include <string>
using namespace std; using namespace std::literals;

string mk_string(integral auto val) { return to_string(val); }
string mk_string(string val) { return '['+val+']'; }
template<typename T>
  requires copyable<T> &&                            // Typanforderung
  requires (T t) { mk_string(t) + mk_string(t); } && // einfache Anforderung
  requires (T t) {                     // zusammengesetzte Anforderung
    {mk_string(t)} -> same_as<string>; // gültiger Ausdruck muss Bedingung erfüllen
  }
string dbl_quote(const T& val) {
  T val2{val};                      // Kopie erzeugen (nur zu Demozwecken)
  return '"' + mk_string(val) + mk_string(val2) + '"';
}
int main() {
  cout << dbl_quote(10) << '\n';    // Ausgabe: "1010"
  cout << dbl_quote("ab"s) << '\n'; // Ausgabe: "[ab][ab]"
  cout << dbl_quote(3.14) << '\n';  //                                  (ERR)  Fehler: keine passende mk_string-Überladung
}

Godbolt Listing lst-0647-godb.cpp, https://godbolt.org/z/orTK9daa3:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/orTK9daa3 
#include <concepts>
#include <iostream>
#include <string>
using namespace std; using namespace std::literals;

string mk_string(integral auto val) { return to_string(val); }
string mk_string(string val) { return '['+val+']'; }
template<typename T>
  requires copyable<T> &&                            // Typanforderung
  requires (T t) { mk_string(t) + mk_string(t); } && // einfache Anforderung
  requires (T t) {                     // zusammengesetzte Anforderung
    {mk_string(t)} -> same_as<string>; // gültiger Ausdruck muss Bedingung erfüllen
  }
string dbl_quote(const T& val) {
  T val2{val};                      // Kopie erzeugen (nur zu Demozwecken)
  return '"' + mk_string(val) + mk_string(val2) + '"';
}
int main() {
  cout << dbl_quote(10) << '\n';    // Ausgabe: "1010"
  cout << dbl_quote("ab"s) << '\n'; // Ausgabe: "[ab][ab]"
  cout << dbl_quote(3.14) << '\n';  //                                  (ERR)  Fehler: keine passende mk_string-Überladung
}

Listing 23.27: Definieren Sie wiederkehrende Anforderungen mit concept.

Book listing lst-0648-book.cpp:

// https://godbolt.org/z/Tcxnr6jTM 
template<typename T>
  concept dbl_quotable = copyable<T> &&
  requires (T t) { mk_string(t) + mk_string(t); } &&
  requires(T t) {
    {mk_string(t)} -> same_as<string>;
  };
string dbl_quote(const dbl_quotable auto& val) {
  auto val2{val}; // Kopie erzeugen (nur zu Demozwecken)
  return '"' + mk_string(val) + mk_string(val2) + '"';
}

Godbolt Listing lst-0648-godb.cpp, https://godbolt.org/z/Tcxnr6jTM:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Tcxnr6jTM 
template<typename T>
  concept dbl_quotable = copyable<T> &&
  requires (T t) { mk_string(t) + mk_string(t); } &&
  requires(T t) {
    {mk_string(t)} -> same_as<string>;
  };
string dbl_quote(const dbl_quotable auto& val) {
  auto val2{val}; // Kopie erzeugen (nur zu Demozwecken)
  return '"' + mk_string(val) + mk_string(val2) + '"';
}

GodboltId:9qsGW6M8Y

Book listing lst-0649-book.cpp:

// https://godbolt.org/z/9qsGW6M8Y 
template<std::ranges::range T>         // eine Range über Typ T
using ValueTypeOfRange = std::ranges::range_value_t<T>;
// oder
template<typename T>
requires std::ranges::range<T>         // eine Range über Typ T
using ValueTypeOfRange = std::ranges::range_value_t<T>;
// ergibt:
ValueTypeOfRange<std::vector<int>> x;  // x ist int
ValueTypeOfRange<std::string> y;       // y ist char
ValueTypeOfRange<std::list<double>> z; // z ist double
ValueTypeOfRange<int> w;               //                                  (ERR)  int ist keine Range

Godbolt Listing lst-0649-godb.cpp, https://godbolt.org/z/9qsGW6M8Y:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9qsGW6M8Y 
template<std::ranges::range T>         // eine Range über Typ T
using ValueTypeOfRange = std::ranges::range_value_t<T>;
// oder
template<typename T>
requires std::ranges::range<T>         // eine Range über Typ T
using ValueTypeOfRange = std::ranges::range_value_t<T>;
// ergibt:
ValueTypeOfRange<std::vector<int>> x;  // x ist int
ValueTypeOfRange<std::string> y;       // y ist char
ValueTypeOfRange<std::list<double>> z; // z ist double
ValueTypeOfRange<int> w;               //                                  (ERR)  int ist keine Range

Listing 23.28: So verwenden Sie Concepts in einem constexpr if.

Book listing lst-0650-book.cpp:

if constexpr std::integral<T> {
  // T ist ein integraler Typ
} else if constexpr std::floating_point<T> {
  // T ist ein Gleitkommatyp
} else {
  // T ist weder noch
}

Listing 23.29: Ein Klassentemplate erhält einen Typ als formalen Parameter.

Book listing lst-0654-book.cpp:

// https://godbolt.org/z/jqzTMxYKv 
template <std::copyable T>      // C++20-Concept
class MyContainer {
    T data_;
public:
    void setData(const T& d) { data_ = d; }
    T getData() const { return data_; }
};

Godbolt Listing lst-0654-godb.cpp, https://godbolt.org/z/jqzTMxYKv:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jqzTMxYKv 
template <std::copyable T>      // C++20-Concept
class MyContainer {
    T data_;
public:
    void setData(const T& d) { data_ = d; }
    T getData() const { return data_; }
};

Listing 23.30: Methodendefinitionen außerhalb des Körpers eines Klassentemplates sind syntaktisch etwas aufwendiger.

Book listing lst-0656-book.cpp:

// https://godbolt.org/z/4fK5WdoG8 
template <std::copyable T>
class MyContainer {
    T data_;
public:
    void setData(const T& d);
    T getData() const;
};
template <std::copyable T>
void MyContainer<T>::setData(const T& d) {
    data_ = d;
}
template <std::copyable T>
T MyContainer<T>::getData() const {
    return data_;
}

Godbolt Listing lst-0656-godb.cpp, https://godbolt.org/z/4fK5WdoG8:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4fK5WdoG8 
template <std::copyable T>
class MyContainer {
    T data_;
public:
    void setData(const T& d);
    T getData() const;
};
template <std::copyable T>
void MyContainer<T>::setData(const T& d) {
    data_ = d;
}
template <std::copyable T>
T MyContainer<T>::getData() const {
    return data_;
}

Listing 23.31: Klassentemplate-Methoden wie Funktionstemplates spezialisieren.

Book listing lst-0657-book.cpp:

// https://godbolt.org/z/M6earoWMn 
#include <iostream>
#include <string>
#include <concepts>    // copyable, C++20
template <std::copyable T>
class MyContainer {
    T data_;
public:
    void setData(const T& d) { data_ = d; } // allgemeiner Fall
    T getData() const { return data_; }     // allgemeiner Fall
};
template<>                                  // Spezialisierung
void MyContainer<std::string>::setData(const std::string& d) {
    data_ = "[" + d + "]";
}
int main() {
    MyContainer<std::string> mcString;
    mcString.setData("Geschichte");
    std::cout << mcString.getData() << '\n';  // Ausgabe: [Geschichte]
    MyContainer<int> mcInt;
    mcInt.setData(5);
    std::cout << mcInt.getData() << '\n';     // Ausgabe: 5
}

Godbolt Listing lst-0657-godb.cpp, https://godbolt.org/z/M6earoWMn:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M6earoWMn 
#include <iostream>
#include <string>
#include <concepts>    // copyable, C++20
template <std::copyable T>
class MyContainer {
    T data_;
public:
    void setData(const T& d) { data_ = d; } // allgemeiner Fall
    T getData() const { return data_; }     // allgemeiner Fall
};
template<>                                  // Spezialisierung
void MyContainer<std::string>::setData(const std::string& d) {
    data_ = "[" + d + "]";
}
int main() {
    MyContainer<std::string> mcString;
    mcString.setData("Geschichte");
    std::cout << mcString.getData() << '\n';  // Ausgabe: [Geschichte]
    MyContainer<int> mcInt;
    mcInt.setData(5);
    std::cout << mcInt.getData() << '\n';     // Ausgabe: 5
}

Listing 23.32: So erzeugen Sie Instanzen aus einer Templateklasse.

Book listing lst-0658-book.cpp:

// https://godbolt.org/z/9vP3o68bW 
#include <iostream>
#include <string>
#include <concepts>    // copyable, C++20
template <std::copyable T>

class MyContainer {
    T data_;
public:
    void setData(const T& d) { data_ = d; }
    T getData() const { return data_; }
};

class IntValue {
    int val_;
public:
    explicit IntValue(int val=0) : val_(val) {}
    int getInt() const { return val_; }
};
int main() {
    // C-Array mit drei MyContainer<double>-Instanzen
    MyContainer<double> dcont[3];
    dcont[0].setData(123.123);
    dcont[1].setData(234.234);
    std::cout << dcont[0].getData() << std::endl;
    std::cout << dcont[1].getData() << std::endl;
    // eigener Datentyp als formaler Parameter
    IntValue ival{100'000};
    MyContainer<IntValue> scont;
    scont.setData(ival);
    std::cout << scont.getData().getInt() << std::endl;
    // string als formaler Parameter
    std::string str("Text");
    MyContainer<std::string> strCont;
    strCont.setData(str);
    std::cout << strCont.getData() << std::endl;
}

Godbolt Listing lst-0658-godb.cpp, https://godbolt.org/z/9vP3o68bW:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9vP3o68bW 
#include <iostream>
#include <string>
#include <concepts>    // copyable, C++20
template <std::copyable T>

class MyContainer {
    T data_;
public:
    void setData(const T& d) { data_ = d; }
    T getData() const { return data_; }
};

class IntValue {
    int val_;
public:
    explicit IntValue(int val=0) : val_(val) {}
    int getInt() const { return val_; }
};
int main() {
    // C-Array mit drei MyContainer<double>-Instanzen
    MyContainer<double> dcont[3];
    dcont[0].setData(123.123);
    dcont[1].setData(234.234);
    std::cout << dcont[0].getData() << std::endl;
    std::cout << dcont[1].getData() << std::endl;
    // eigener Datentyp als formaler Parameter
    IntValue ival{100'000};
    MyContainer<IntValue> scont;
    scont.setData(ival);
    std::cout << scont.getData().getInt() << std::endl;
    // string als formaler Parameter
    std::string str("Text");
    MyContainer<std::string> strCont;
    strCont.setData(str);
    std::cout << strCont.getData() << std::endl;
}

Listing 23.33: Aus Konstruktorargumenten auf Templateparameter schließen

Book listing lst-0659-book.cpp:

// https://godbolt.org/z/7KzcWE8Pz 
#include <string>
#include <vector>
#include <set>
#include <tuple>
#include <memory> // shared_ptr
template <typename T>
class MyStuff {
    T data_;
public:
    MyStuff() : data_{} {}             // default c'tor
    MyStuff(const T& d) : data_{d} { } // copy c'tor
    T getStuff() const { return data_; }
};
class IntValue {
    int val_;
public:
    explicit IntValue(int val=0) : val_(val) {}
    int getInt() const { return val_; }
};
int main() {
    MyStuff intStuff(12);              // wird zu MyStuff<int>
    std::vector vs{ 1,2,3,4 };         // wird zu vector<int>
    MyStuff ivalStuff{ IntValue{33} }; // wird zu MyStuff<IntValue>
    std::tuple tpl{ 23, 'a' };         // wird zu tuple<int,char>
    std::set zweiDrei (vs.begin()+1, vs.end()-1); // wird zu set<int>
    // Kann der Compiler nicht deduzieren:
    MyStuff<double> dblStuff;              // kein Konstruktorargument
    std::vector<char> vcs(10);             // Größe 10, aber von welchem Typ?
    std::shared_ptr<int> ptr{new int{88}}; // keine Regel für int*
}

Godbolt Listing lst-0659-godb.cpp, https://godbolt.org/z/7KzcWE8Pz:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7KzcWE8Pz 
#include <string>
#include <vector>
#include <set>
#include <tuple>
#include <memory> // shared_ptr
template <typename T>
class MyStuff {
    T data_;
public:
    MyStuff() : data_{} {}             // default c'tor
    MyStuff(const T& d) : data_{d} { } // copy c'tor
    T getStuff() const { return data_; }
};
class IntValue {
    int val_;
public:
    explicit IntValue(int val=0) : val_(val) {}
    int getInt() const { return val_; }
};
int main() {
    MyStuff intStuff(12);              // wird zu MyStuff<int>
    std::vector vs{ 1,2,3,4 };         // wird zu vector<int>
    MyStuff ivalStuff{ IntValue{33} }; // wird zu MyStuff<IntValue>
    std::tuple tpl{ 23, 'a' };         // wird zu tuple<int,char>
    std::set zweiDrei (vs.begin()+1, vs.end()-1); // wird zu set<int>
    // Kann der Compiler nicht deduzieren:
    MyStuff<double> dblStuff;              // kein Konstruktorargument
    std::vector<char> vcs(10);             // Größe 10, aber von welchem Typ?
    std::shared_ptr<int> ptr{new int{88}}; // keine Regel für int*
}

Listing 23.34: Sie können make_-Hilfsfunktionen und auto schon lange verwenden.

Book listing lst-0660-book.cpp:

auto tpl = std::make_tuple( 5, 'x' );
auto ptr = std::make_shared( 5 );

GodboltId:dMTnbT1v4

Book listing lst-0661-book.cpp:

// https://godbolt.org/z/dMTnbT1v4 
#include <iostream>
#include <concepts>    // copyable, C+20
template<std::copyable T, std::copyable U>
class MyPair {
    T data01_;
    U data02_;
public:
    MyPair(const T& t,const U& u) : data01_{t}, data02_{u} {}
    void print(std::ostream& os) const {
        os << data01_ << " : " << data02_ << std::endl;
    }
};
int main() {
    std::string month{"Januar"};
    int temp = -5;
    MyPair<std::string, int> temperatur{month, temp};
    temperatur.print(std::cout);
}

Godbolt Listing lst-0661-godb.cpp, https://godbolt.org/z/dMTnbT1v4:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dMTnbT1v4 
#include <iostream>
#include <concepts>    // copyable, C+20
template<std::copyable T, std::copyable U>
class MyPair {
    T data01_;
    U data02_;
public:
    MyPair(const T& t,const U& u) : data01_{t}, data02_{u} {}
    void print(std::ostream& os) const {
        os << data01_ << " : " << data02_ << std::endl;
    }
};
int main() {
    std::string month{"Januar"};
    int temp = -5;
    MyPair<std::string, int> temperatur{month, temp};
    temperatur.print(std::cout);
}

GodboltId:jbafeEdoW

Book listing lst-0662-book.cpp:

// https://godbolt.org/z/jbafeEdoW 
#include <iostream>
#include <concepts>    // copyable, C++20
template<std::copyable T, std::copyable U=T>
class MyPair {
    T data01_;
    U data02_;
public:
    MyPair(const T& t,const U& u) : data01_{t}, data02_{u} {}
    void print(std::ostream& os) const {
        os << data01_ << " : " << data02_ << std::endl;
    }
};
int main() {
    MyPair<double> zahlen{11.11, 22.22};
    zahlen.print(std::cout);
}

Godbolt Listing lst-0662-godb.cpp, https://godbolt.org/z/jbafeEdoW:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jbafeEdoW 
#include <iostream>
#include <concepts>    // copyable, C++20
template<std::copyable T, std::copyable U=T>
class MyPair {
    T data01_;
    U data02_;
public:
    MyPair(const T& t,const U& u) : data01_{t}, data02_{u} {}
    void print(std::ostream& os) const {
        os << data01_ << " : " << data02_ << std::endl;
    }
};
int main() {
    MyPair<double> zahlen{11.11, 22.22};
    zahlen.print(std::cout);
}

GodboltId:xPrheoeEd

Book listing lst-0665-book.cpp:

// https://godbolt.org/z/xPrheoeEd 
#include <iostream>
template <typename T, size_t n=1>    // Non-Type-Parameter mit Defaultwert
class FixedArray {
    T data_[n] {0};                  // Non-Type-Parameter verwenden
public:
    T& operator[](size_t index) { return data_[index]; }
    static constexpr size_t size() { return n; }
    void print(std::ostream &os) const {
        for(auto it : data_)
            os << it << ' ';
        os << '\n';
    }
};
int main() {
    FixedArray<int,10> vals {};        // n = 10
    for(size_t idx=0; idx < vals.size(); ++idx) {
        vals[idx] = idx+idx;
    }
    vals.print(std::cout);             // Ausgabe: 0 2 4 6 8 10 12 14 16 18
    FixedArray<double> dvals;          // Defaultparameter für n
    std::cout << dvals.size() << '\n'; // Ausgabe: 1
}

Godbolt Listing lst-0665-godb.cpp, https://godbolt.org/z/xPrheoeEd:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xPrheoeEd 
#include <iostream>
template <typename T, size_t n=1>    // Non-Type-Parameter mit Defaultwert
class FixedArray {
    T data_[n] {0};                  // Non-Type-Parameter verwenden
public:
    T& operator[](size_t index) { return data_[index]; }
    static constexpr size_t size() { return n; }
    void print(std::ostream &os) const {
        for(auto it : data_)
            os << it << ' ';
        os << '\n';
    }
};
int main() {
    FixedArray<int,10> vals {};        // n = 10
    for(size_t idx=0; idx < vals.size(); ++idx) {
        vals[idx] = idx+idx;
    }
    vals.print(std::cout);             // Ausgabe: 0 2 4 6 8 10 12 14 16 18
    FixedArray<double> dvals;          // Defaultparameter für n
    std::cout << dvals.size() << '\n'; // Ausgabe: 1
}

GodboltId:Y6v6cKE3v

Book listing lst-0670-book.cpp:

// https://godbolt.org/z/Y6v6cKE3v 
#include <string>
#include <tuple>
#include <concepts>             // copyable, C++20
template <std::copyable T, std::copyable U=T> // allgemeiner Fall
class MyPair {
    T data01_;
    U data02_;
public:
    MyPair(const T& t, const U& u) : data01_{t}, data02_{u} {}
};
template <std::copyable T>      // teilweise Spezialisierung, T bleibt formal
class MyPair<T, std::string> {  // U ist auf string spezialisiert
    std::tuple<T,std::string> data_;
public:
    MyPair(const T& t, const std::string& str) : data_{t, str} { }
};
template <std::copyable U>      // teilweise Spezialisierung, U bleibt formal
class MyPair<std::string, U> {  // T ist auf string spezialisiert
    std::tuple<std::string, U> data_;
public:
    MyPair(const std::string& str, const U& u) : data_{str, u} { }
};
int main() {
  // nutzt partielle Spezialisierung
  MyPair<int,std::string> intString{1, "a"};
  MyPair<std::string,int> stringInt{"b", 2};

  MyPair<int,int> intInt{3,4};                     // nutzt allgemeinen Fall
  MyPair intInt2{3,4};                             // auch MyPair<int,int>
  MyPair<std::string,std::string> strStr{"c","d"}; //                                          (ERR)  mehrdeutig
}

Godbolt Listing lst-0670-godb.cpp, https://godbolt.org/z/Y6v6cKE3v:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Y6v6cKE3v 
#include <string>
#include <tuple>
#include <concepts>             // copyable, C++20
template <std::copyable T, std::copyable U=T> // allgemeiner Fall
class MyPair {
    T data01_;
    U data02_;
public:
    MyPair(const T& t, const U& u) : data01_{t}, data02_{u} {}
};
template <std::copyable T>      // teilweise Spezialisierung, T bleibt formal
class MyPair<T, std::string> {  // U ist auf string spezialisiert
    std::tuple<T,std::string> data_;
public:
    MyPair(const T& t, const std::string& str) : data_{t, str} { }
};
template <std::copyable U>      // teilweise Spezialisierung, U bleibt formal
class MyPair<std::string, U> {  // T ist auf string spezialisiert
    std::tuple<std::string, U> data_;
public:
    MyPair(const std::string& str, const U& u) : data_{str, u} { }
};
int main() {
  // nutzt partielle Spezialisierung
  MyPair<int,std::string> intString{1, "a"};
  MyPair<std::string,int> stringInt{"b", 2};

  MyPair<int,int> intInt{3,4};                     // nutzt allgemeinen Fall
  MyPair intInt2{3,4};                             // auch MyPair<int,int>
  MyPair<std::string,std::string> strStr{"c","d"}; //                                          (ERR)  mehrdeutig
}

GodboltId:baPeoTbM8

Book listing lst-0671-book.cpp:

// https://godbolt.org/z/baPeoTbM8 
template<>   // vollständige Spezialisierung
class MyPair<std::string, std::string> {
    std::vector<std::string> data_;
public:
    MyPair(const std::string& t, const std::string& u) : data_{t, u} { }
};
int main() {
    // nutzt die vollständige Spezialisierung:
    MyPair<std::string,std::string> strStr{"c","d"};
}

Godbolt Listing lst-0671-godb.cpp, https://godbolt.org/z/baPeoTbM8:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/baPeoTbM8 
template<>   // vollständige Spezialisierung
class MyPair<std::string, std::string> {
    std::vector<std::string> data_;
public:
    MyPair(const std::string& t, const std::string& u) : data_{t, u} { }
};
int main() {
    // nutzt die vollständige Spezialisierung:
    MyPair<std::string,std::string> strStr{"c","d"};
}

Listing 23.35: Ein Template mit einer variablen Anzahl von Argumenten

Book listing lst-0672-book.cpp:

// https://godbolt.org/z/c6W6EWb1K 
#include <typeinfo>               // operator typeid
#include <typeindex>              // type_index
#include <map>
#include <string>
#include <iostream>
template <typename T>
void output(std::ostream& os, T val) { // einen Typnamen ausgeben
    // static: beim ersten Mal initialisiert
    static const std::map<std::type_index,std::string> type_names {
        { std::type_index(typeid(const char*)), "const char*"},
        { std::type_index(typeid(char)), "char"},
        { std::type_index(typeid(int)), "int"},
        { std::type_index(typeid(double)), "double"},
        { std::type_index(typeid(bool)), "bool"},
    };
    const std::string name = type_names.at(std::type_index(typeid(T)));
    os << name << ": " << val << '\n';
}
// rekursives variadisches Funktionstemplate:
template<typename First, typename ... Rest>
void output(std::ostream &os, First first, Rest ... rest) {
    output(os, first);           // einzelner Aufruf mit vorderstem Element
    output(os, rest ...);        // Rekursion mit Rest der Elemente
}
int main() {
  output(std::cout, 3.1415);                      // normales Template
  output(std::cout, "ende", 2, 3.14, 'A', false); // rekursive variadische Funktion
}

Godbolt Listing lst-0672-godb.cpp, https://godbolt.org/z/c6W6EWb1K:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/c6W6EWb1K 
#include <typeinfo>               // operator typeid
#include <typeindex>              // type_index
#include <map>
#include <string>
#include <iostream>
template <typename T>
void output(std::ostream& os, T val) { // einen Typnamen ausgeben
    // static: beim ersten Mal initialisiert
    static const std::map<std::type_index,std::string> type_names {
        { std::type_index(typeid(const char*)), "const char*"},
        { std::type_index(typeid(char)), "char"},
        { std::type_index(typeid(int)), "int"},
        { std::type_index(typeid(double)), "double"},
        { std::type_index(typeid(bool)), "bool"},
    };
    const std::string name = type_names.at(std::type_index(typeid(T)));
    os << name << ": " << val << '\n';
}
// rekursives variadisches Funktionstemplate:
template<typename First, typename ... Rest>
void output(std::ostream &os, First first, Rest ... rest) {
    output(os, first);           // einzelner Aufruf mit vorderstem Element
    output(os, rest ...);        // Rekursion mit Rest der Elemente
}
int main() {
  output(std::cout, 3.1415);                      // normales Template
  output(std::cout, "ende", 2, 3.14, 'A', false); // rekursive variadische Funktion
}

GodboltId:8oYaWYnbx

Book listing lst-0678-book.cpp:

// https://godbolt.org/z/8oYaWYnbx 
#include <tuple>
#include <iostream>
template<typename ... Args>
auto conv2tuple(Args ... args) {
    return std::make_tuple(args...);
}
int main() {
    auto mytuple = conv2tuple("ende", 2, 3.14, 'A', false);
    std::cout << std::get<2>(mytuple) << '\n'; // Ausgabe: 3.14
}

Godbolt Listing lst-0678-godb.cpp, https://godbolt.org/z/8oYaWYnbx:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8oYaWYnbx 
#include <tuple>
#include <iostream>
template<typename ... Args>
auto conv2tuple(Args ... args) {
    return std::make_tuple(args...);
}
int main() {
    auto mytuple = conv2tuple("ende", 2, 3.14, 'A', false);
    std::cout << std::get<2>(mytuple) << '\n'; // Ausgabe: 3.14
}

Listing 23.36: Eigene Literaloperatoren

Book listing lst-0679-book.cpp:

// https://godbolt.org/z/cjx49ef19 
namespace my {
  Complex operator"" _i(const char*); // 0+ni
  Complex operator"" _j(long double); // n+0i
  Puzzle operator"" _puzzle(const char*, size_t);
}
using namespace my;
Complex imag4 = 4_i;      // operator"" _i(const char*)
Complex real3 = 3.331_j;  // operator"" _j(long double)

Puzzle p1 = "oXo"         // operator"" _puzzle(const char*, size_t)
            "XoX"_puzzle;

Godbolt Listing lst-0679-godb.cpp, https://godbolt.org/z/cjx49ef19:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cjx49ef19 
namespace my {
  Complex operator"" _i(const char*); // 0+ni
  Complex operator"" _j(long double); // n+0i
  Puzzle operator"" _puzzle(const char*, size_t);
}
using namespace my;
Complex imag4 = 4_i;      // operator"" _i(const char*)
Complex real3 = 3.331_j;  // operator"" _j(long double)

Puzzle p1 = "oXo"         // operator"" _puzzle(const char*, size_t)
            "XoX"_puzzle;

Listing 23.37: Welches Literal führt zu welchem Operatoraufruf?

Book listing lst-0680-book.cpp:

// https://godbolt.org/z/Mevoshb3o 
namespace lits {
  long double operator"" _w(long double);
  string      operator"" _w(const char16_t*, size_t);
  unsigned    operator"" _w(const char*);
}
int main() {
  using namespace lits;
  1.2_w;       // operator"" _w(long double), mit (1.2L)
  u"one"_w;    // operator"" _w(char16_t, size_t), mit (u"one", 3)
  12_w;        // operator"" _w(const char*), mit "12"
  "two"_w;     //                                  (ERR)  operator"" _w(const char*, size_t) nicht definiert
}

Godbolt Listing lst-0680-godb.cpp, https://godbolt.org/z/Mevoshb3o:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Mevoshb3o 
namespace lits {
  long double operator"" _w(long double);
  string      operator"" _w(const char16_t*, size_t);
  unsigned    operator"" _w(const char*);
}
int main() {
  using namespace lits;
  1.2_w;       // operator"" _w(long double), mit (1.2L)
  u"one"_w;    // operator"" _w(char16_t, size_t), mit (u"one", 3)
  12_w;        // operator"" _w(const char*), mit "12"
  "two"_w;     //                                  (ERR)  operator"" _w(const char*, size_t) nicht definiert
}

Listing 23.38: Ein Template für Literale der exakten Länge zwei

Book listing lst-0681-book.cpp:

// https://godbolt.org/z/5rdzn8YP4 
namespace lits {
  // allgemeines Template
  template<char...> int operator"" _bin2();
  // Spezialisierungen
  template<> int operator"" _bin2<'0','0'>() { return 0; }
  template<> int operator"" _bin2<'0','1'>() { return 1; }
  template<> int operator"" _bin2<'1','0'>() { return 2; }
  template<> int operator"" _bin2<'1','1'>() { return 3; }
}
int main() {
  using namespace lits;
  int one   = 01_bin2;
  int three = 11_bin2;
}

Godbolt Listing lst-0681-godb.cpp, https://godbolt.org/z/5rdzn8YP4:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5rdzn8YP4 
namespace lits {
  // allgemeines Template
  template<char...> int operator"" _bin2();
  // Spezialisierungen
  template<> int operator"" _bin2<'0','0'>() { return 0; }
  template<> int operator"" _bin2<'0','1'>() { return 1; }
  template<> int operator"" _bin2<'1','0'>() { return 2; }
  template<> int operator"" _bin2<'1','1'>() { return 3; }
}
int main() {
  using namespace lits;
  int one   = 01_bin2;
  int three = 11_bin2;
}

Listing 23.39: Rekursive Definition für beliebige Literallängen

Book listing lst-0682-book.cpp:

// https://godbolt.org/z/sbxojqjqs 
namespace lits {
  // Templatehilfsfunktion für ein Argument
  template<char C> int bin();  // allgemeiner Fall
  template<>       int bin<'1'>() { return 1; } // Spezialisierung.
  template<>       int bin<'0'>() { return 0; } // Spezialisierung.
  // Templatehilfsfunktion ab zwei Argumente
  template<char C, char D, char... ES>
  int bin() {
    return bin<C>() << (sizeof...(ES)+1) | bin<D,ES...>(); // Bit-Shift, Bit-Oder
  }
  // eigentlicher operator""
  template<char...CS> int operator"" _bin()
    { return bin<CS...>(); };
}
int main() {
  using namespace lits;
  int eins = 1_bin;
  int acht = 1000_bin;
  int neun = 1001_bin;
  int zehn = 1010_bin;
  int elf  = 1011_bin;
  int hundertachtundzwanzig = 10000000_bin;
}

Godbolt Listing lst-0682-godb.cpp, https://godbolt.org/z/sbxojqjqs:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sbxojqjqs 
namespace lits {
  // Templatehilfsfunktion für ein Argument
  template<char C> int bin();  // allgemeiner Fall
  template<>       int bin<'1'>() { return 1; } // Spezialisierung.
  template<>       int bin<'0'>() { return 0; } // Spezialisierung.
  // Templatehilfsfunktion ab zwei Argumente
  template<char C, char D, char... ES>
  int bin() {
    return bin<C>() << (sizeof...(ES)+1) | bin<D,ES...>(); // Bit-Shift, Bit-Oder
  }
  // eigentlicher operator""
  template<char...CS> int operator"" _bin()
    { return bin<CS...>(); };
}
int main() {
  using namespace lits;
  int eins = 1_bin;
  int acht = 1000_bin;
  int neun = 1001_bin;
  int zehn = 1010_bin;
  int elf  = 1011_bin;
  int hundertachtundzwanzig = 10000000_bin;
}

Listing 23.40: Das neue if constexpr spart Funktionsspezialisierungen.

Book listing lst-0683-book.cpp:

// https://godbolt.org/z/KvsGh4f1v 
namespace lits {
  // Templatehilfsfunktion für ein Argument
  template<char C> int bin() {  // allgemeiner Fall
    if constexpr (C=='0') return 0;
    else if constexpr (C=='1') return 1;
  }
  // Templatehilfsfunktion ab zwei Argumente
  // …
}

Godbolt Listing lst-0683-godb.cpp, https://godbolt.org/z/KvsGh4f1v:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KvsGh4f1v 
namespace lits {
  // Templatehilfsfunktion für ein Argument
  template<char C> int bin() {  // allgemeiner Fall
    if constexpr (C=='0') return 0;
    else if constexpr (C=='1') return 1;
  }
  // Templatehilfsfunktion ab zwei Argumente
  // …
}

Listing 23.41: Mit Faltausdrücken werden variadische Templates einfacher.

Book listing lst-0684-book.cpp:

// https://godbolt.org/z/cPoEjqzM7 
#include <iostream>
#include <string>
namespace lits {
    // operator"" _sx
    template<char...CS> std::string operator"" _sx() {
        return (std::string{} + ... + CS); // ein Faltausdruck
    };
}
int main() {
    using namespace lits;
    std::cout << 10000000_sx << '\n';     // Ausgabe: 10000000
    std::cout << 10'000'000_sx << '\n';   // Ausgabe: 10'000'000
    std::cout << 0x00af_sx << '\n';       // Ausgabe: 0x00af
    std::cout << 0x0'c'0'a'f_sx << '\n';  // Ausgabe: 0x0'c'0'a'f
    std::cout << 007_sx << '\n';          // Ausgabe: 007
    std::cout << 0b01_sx << '\n';         // Ausgabe: 0b01
}

Godbolt Listing lst-0684-godb.cpp, https://godbolt.org/z/cPoEjqzM7:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cPoEjqzM7 
#include <iostream>
#include <string>
namespace lits {
    // operator"" _sx
    template<char...CS> std::string operator"" _sx() {
        return (std::string{} + ... + CS); // ein Faltausdruck
    };
}
int main() {
    using namespace lits;
    std::cout << 10000000_sx << '\n';     // Ausgabe: 10000000
    std::cout << 10'000'000_sx << '\n';   // Ausgabe: 10'000'000
    std::cout << 0x00af_sx << '\n';       // Ausgabe: 0x00af
    std::cout << 0x0'c'0'a'f_sx << '\n';  // Ausgabe: 0x0'c'0'a'f
    std::cout << 007_sx << '\n';          // Ausgabe: 007
    std::cout << 0b01_sx << '\n';         // Ausgabe: 0b01
}

Listing 23.42: Ob vorverarbeitet oder roh besser ist, hängt von der Anwendung ab.

Book listing lst-0685-book.cpp:

// https://godbolt.org/z/Yd4sser5j 
#include <complex>
// rohe Form
int operator"" _dual(const char*);
int answer = 101010_dual;    // dezimal 42
// vorverarbeitete Form
std::complex<long double> operator"" _i(long double d) {
  return std::complex<long double>(0, d);
}
auto val = 3.14_i; // val = std::complex<long double>(0, 3.14)

Godbolt Listing lst-0685-godb.cpp, https://godbolt.org/z/Yd4sser5j:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Yd4sser5j 
#include <complex>
// rohe Form
int operator"" _dual(const char*);
int answer = 101010_dual;    // dezimal 42
// vorverarbeitete Form
std::complex<long double> operator"" _i(long double d) {
  return std::complex<long double>(0, d);
}
auto val = 3.14_i; // val = std::complex<long double>(0, 3.14)

Listing 24.1: Für Bereiche nutzen Sie Iteratorpaare oder ab C++23 Ranges.

Book listing lst-0694-book.cpp:

// https://godbolt.org/z/qGrYPrqYn 
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector nums{ 1,2,3 };
    vector vier{ 4,5,6 };
    vector sieben{ 7,8,9 } ;
    nums.insert(nums.begin(), vier.begin(), vier.end());
    cout << nums.size() << "\n";                      // Ausgabe: 9
    nums.insert_range(nums.begin(), sieben);          // C++23
}

Godbolt Listing lst-0694-godb.cpp, https://godbolt.org/z/qGrYPrqYn:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qGrYPrqYn 
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector nums{ 1,2,3 };
    vector vier{ 4,5,6 };
    vector sieben{ 7,8,9 } ;
    nums.insert(nums.begin(), vier.begin(), vier.end());
    cout << nums.size() << "\n";                      // Ausgabe: 9
    nums.insert_range(nums.begin(), sieben);          // C++23
}

Listing 24.2: Ein Paar Iteratoren definiert einen Bereich von Elementen.

Book listing lst-0695-book.cpp:

// https://godbolt.org/z/M1d9jEP74 
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector numbers{ 1,2,3,4,5 };
    numbers.erase(numbers.begin(), numbers.end());
    cout << numbers.size() << "\n"; // Ausgabe: 0
}

Godbolt Listing lst-0695-godb.cpp, https://godbolt.org/z/M1d9jEP74:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M1d9jEP74 
#include <vector>
#include <iostream>
using namespace std;
int main() {
    vector numbers{ 1,2,3,4,5 };
    numbers.erase(numbers.begin(), numbers.end());
    cout << numbers.size() << "\n"; // Ausgabe: 0
}

Listing 24.3: Verwendet indirekt begin() und end() des Containers

Book listing lst-0696-book.cpp:

// https://godbolt.org/z/Yv3vcxPv5 
#include <vector>
#include <iostream>
int main() {
    std::vector<int> numbers{ 1,2,3,4,5 };
    for(auto val : numbers) {
        std::cout << val << ' ';
    }
    std::cout << '\n';
}

Godbolt Listing lst-0696-godb.cpp, https://godbolt.org/z/Yv3vcxPv5:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Yv3vcxPv5 
#include <vector>
#include <iostream>
int main() {
    std::vector<int> numbers{ 1,2,3,4,5 };
    for(auto val : numbers) {
        std::cout << val << ' ';
    }
    std::cout << '\n';
}

GodboltId:babK485oT

Book listing lst-0697-book.cpp:

// https://godbolt.org/z/babK485oT 
#include <vector>
#include <iostream>
int main() {
    std::vector<int> numbers{ 1,2,3,4,5 };
    for(auto it = begin(numbers); it != end(numbers); ++it) {
        auto val = *it;
        std::cout << val << ' ';
    }
    std::cout << '\n';
}

Godbolt Listing lst-0697-godb.cpp, https://godbolt.org/z/babK485oT:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/babK485oT 
#include <vector>
#include <iostream>
int main() {
    std::vector<int> numbers{ 1,2,3,4,5 };
    for(auto it = begin(numbers); it != end(numbers); ++it) {
        auto val = *it;
        std::cout << val << ' ';
    }
    std::cout << '\n';
}

GodboltId:nj14e6Wq4

Book listing lst-0698-book.cpp:

// https://godbolt.org/z/nj14e6Wq4 
#include <set>
#include <iostream>
int main() {
    std::set<int> numbers{ 10, 20, 90 };
    auto nein = numbers.find(30);
    if(nein == numbers.end()) { std::cout << "nicht da.\n"; }
    auto ja = numbers.find(20);
    if(ja != numbers.end()) { std::cout << *ja << '\n'; }
}

Godbolt Listing lst-0698-godb.cpp, https://godbolt.org/z/nj14e6Wq4:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/nj14e6Wq4 
#include <set>
#include <iostream>
int main() {
    std::set<int> numbers{ 10, 20, 90 };
    auto nein = numbers.find(30);
    if(nein == numbers.end()) { std::cout << "nicht da.\n"; }
    auto ja = numbers.find(20);
    if(ja != numbers.end()) { std::cout << *ja << '\n'; }
}

Listing 24.4: Ein Algorithmus nach dem anderen mit Iteratoren

Book listing lst-0699-book.cpp:

// https://godbolt.org/z/arfee3TTP 
using namespace std;
vector in { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
vector<int> tmp{};
vector<int> out{};
copy_if(in.begin(), in.end(), back_inserter(tmp), [](int i) { return i%3 == 0; });
transform(tmp.begin(), tmp.end(), back_inserter(out), [](int i) {return i*i; });

Godbolt Listing lst-0699-godb.cpp, https://godbolt.org/z/arfee3TTP:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/arfee3TTP 
using namespace std;
vector in { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
vector<int> tmp{};
vector<int> out{};
copy_if(in.begin(), in.end(), back_inserter(tmp), [](int i) { return i%3 == 0; });
transform(tmp.begin(), tmp.end(), back_inserter(out), [](int i) {return i*i; });

Listing 24.5: Eine Pipeline aus Views statt Algorithmen

Book listing lst-0700-book.cpp:

// https://godbolt.org/z/TG1qd31Mq 
using namespace std; namespace views = std::ranges::views;
vector in { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
auto out = in
    | views::filter([](int i) { return i%3 == 0; })
    | views::transform([](int i) {return i*i; });

Godbolt Listing lst-0700-godb.cpp, https://godbolt.org/z/TG1qd31Mq:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TG1qd31Mq 
using namespace std; namespace views = std::ranges::views;
vector in { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
auto out = in
    | views::filter([](int i) { return i%3 == 0; })
    | views::transform([](int i) {return i*i; });

Listing 24.8: Für »const«-Objekte liefern »begin()« und »end()« einen »const_iterator« zurück.

Book listing lst-0702-book.cpp:

// https://godbolt.org/z/dxb98rWzo 
#include <iostream>                // cout
#include <vector>
using std::vector;

vector<int> createData(size_t sz) {
    return vector<int>(sz);        // sz x null
}
void fibonacci(vector<int> &data) {
    for(auto it = begin(data)+2; it != end(data); ++it) { // iterator it
        *it = *(it-1) + *(it-2);
    }
}

std::ostream& show(std::ostream &os, const vector<int> &data) {
    for(auto it=begin(data); it != end(data); ++it)       // const_iterator it
        std::cout << *it << " ";
    return os;
}

int main() {
    vector<int> data = createData(10);
    data[0] = 1;
    data[1] = 1;
    fibonacci(data);
    show(std::cout, data) << "\n";
}

Godbolt Listing lst-0702-godb.cpp, https://godbolt.org/z/dxb98rWzo:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dxb98rWzo 
#include <iostream>                // cout
#include <vector>
using std::vector;

vector<int> createData(size_t sz) {
    return vector<int>(sz);        // sz x null
}
void fibonacci(vector<int> &data) {
    for(auto it = begin(data)+2; it != end(data); ++it) { // iterator it
        *it = *(it-1) + *(it-2);
    }
}

std::ostream& show(std::ostream &os, const vector<int> &data) {
    for(auto it=begin(data); it != end(data); ++it)       // const_iterator it
        std::cout << *it << " ";
    return os;
}

int main() {
    vector<int> data = createData(10);
    data[0] = 1;
    data[1] = 1;
    fibonacci(data);
    show(std::cout, data) << "\n";
}

Listing 24.9: Iteratoradapter verändern das Verhalten von Operationen.

Book listing lst-0706-book.cpp:

// https://godbolt.org/z/7xYcqqh68 
#include <vector>
#include <iostream>   // cout
#include <iterator>   // ostream_iterator
#include <algorithm>  // copy

int main() {
  std::vector data { 1, 2, 3, 7, 9, 10 };
  std::ostream_iterator<int> out_it (std::cout,", "); // bei Zuweisung nach cout
  std::copy(data.begin(), data.end(), out_it); // alle Elemente in den Iterator
  std::cout << "\n";                           // Ausgabe: 1, 2, 3, 7, 9, 10,
  // oder ab C++20 mit Ranges:
  std::ranges::copy(data, out_it);
  std::cout << "\n";                           // Ausgabe: 1, 2, 3, 7, 9, 10,
}

Godbolt Listing lst-0706-godb.cpp, https://godbolt.org/z/7xYcqqh68:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7xYcqqh68 
#include <vector>
#include <iostream>   // cout
#include <iterator>   // ostream_iterator
#include <algorithm>  // copy

int main() {
  std::vector data { 1, 2, 3, 7, 9, 10 };
  std::ostream_iterator<int> out_it (std::cout,", "); // bei Zuweisung nach cout
  std::copy(data.begin(), data.end(), out_it); // alle Elemente in den Iterator
  std::cout << "\n";                           // Ausgabe: 1, 2, 3, 7, 9, 10,
  // oder ab C++20 mit Ranges:
  std::ranges::copy(data, out_it);
  std::cout << "\n";                           // Ausgabe: 1, 2, 3, 7, 9, 10,
}

Listing 24.10: Ein (zu) einfacher Allokator und sein Einsatz

Book listing lst-0707-book.cpp:

// https://godbolt.org/z/TzvK9hTsj 
#include <set>
#include <vector>
#include <iostream>
template<class T> class HappsAllocator  {
public:
    using value_type = T;
    T* allocate(size_t count) {
        size_t add = sizeof(T)*count;
        std::cout << "allocate("<<add<<"/"<<(buf_.size()-current_)<<")\n";
        if(current_+add > buf_.size()) throw std::bad_alloc{};
        char* result = buf_.data()+current_;
        current_ += add;
        return reinterpret_cast<T*>(result);
    }
    void deallocate(T* p, size_t count) {
        size_t del = sizeof(T)*count;
        std::cout << "deallocate("<<del<<")\n";
        if(del==current_ && p==reinterpret_cast<T*>(buf_.data())) {
            std::cout << "...alles frei.\n";
            current_ = 0;// alles wieder freigeben
        }
    }
    HappsAllocator() : HappsAllocator{1024} {}
    explicit HappsAllocator(size_t mx)
      : buf_(mx, 0), current_{0} { }
private:
       std::vector<char> buf_;
       size_t current_;
};
int main() {
    constexpr size_t ANZ = 1*1000*1000;
    using Happs = HappsAllocator<int>;
    try {
        Happs happs(ANZ*sizeof(int)); // Allokator vorbereiten
        std::vector<int,Happs> data(happs);
        data.reserve(ANZ);            // Speicher in einem Schwung holen
        for(int val=0; val < (int)ANZ; ++val)
            data.push_back(val);
    } catch(std::bad_alloc &ex) {
        std::cout << "Speicher alle.\n";
    }
}

Godbolt Listing lst-0707-godb.cpp, https://godbolt.org/z/TzvK9hTsj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TzvK9hTsj 
#include <set>
#include <vector>
#include <iostream>
template<class T> class HappsAllocator  {
public:
    using value_type = T;
    T* allocate(size_t count) {
        size_t add = sizeof(T)*count;
        std::cout << "allocate("<<add<<"/"<<(buf_.size()-current_)<<")\n";
        if(current_+add > buf_.size()) throw std::bad_alloc{};
        char* result = buf_.data()+current_;
        current_ += add;
        return reinterpret_cast<T*>(result);
    }
    void deallocate(T* p, size_t count) {
        size_t del = sizeof(T)*count;
        std::cout << "deallocate("<<del<<")\n";
        if(del==current_ && p==reinterpret_cast<T*>(buf_.data())) {
            std::cout << "...alles frei.\n";
            current_ = 0;// alles wieder freigeben
        }
    }
    HappsAllocator() : HappsAllocator{1024} {}
    explicit HappsAllocator(size_t mx)
      : buf_(mx, 0), current_{0} { }
private:
       std::vector<char> buf_;
       size_t current_;
};
int main() {
    constexpr size_t ANZ = 1*1000*1000;
    using Happs = HappsAllocator<int>;
    try {
        Happs happs(ANZ*sizeof(int)); // Allokator vorbereiten
        std::vector<int,Happs> data(happs);
        data.reserve(ANZ);            // Speicher in einem Schwung holen
        for(int val=0; val < (int)ANZ; ++val)
            data.push_back(val);
    } catch(std::bad_alloc &ex) {
        std::cout << "Speicher alle.\n";
    }
}

Listing 24.11: Typaliase sind manchmal klarer als die konkreten Typen.

Book listing lst-0709-book.cpp:

// https://godbolt.org/z/c97qra3M7 
#include <vector>
#include <map>
#include <iostream>
using std::cout; using std::ostream;
template<typename K, typename T>
ostream& operator<<(ostream& os, std::pair<const K,T> value) {
    return os << '[' << value.first << ':' << value.second << ']';
}
int main() {
  {
    using Cont = std::vector<int>;
    Cont cont{ 1, 2, 3, 4, 5, 6 };
    Cont::size_type sz = cont.size();
    cout << "size=" << sz << " content= ";
    for(Cont::const_iterator it = cont.begin(); it != cont.end(); ++it) 
        cout << *it << ' ';
    cout << '\n';
  }
  {
    using Cont = std::map<int,char>;
    Cont cont{ {1,'a'}, {2,'b'}, {3,'c'}, {4,'d'}, {5,'e'}, {6,'f'} };
    Cont::size_type sz = cont.size();
    cout << "size=" << sz << " content= ";
    for(Cont::const_iterator it = cont.begin(); it != cont.end(); ++it) 
        cout << *it << ' ';
    cout << '\n';
  }
}

Godbolt Listing lst-0709-godb.cpp, https://godbolt.org/z/c97qra3M7:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/c97qra3M7 
#include <vector>
#include <map>
#include <iostream>
using std::cout; using std::ostream;
template<typename K, typename T>
ostream& operator<<(ostream& os, std::pair<const K,T> value) {
    return os << '[' << value.first << ':' << value.second << ']';
}
int main() {
  {
    using Cont = std::vector<int>;
    Cont cont{ 1, 2, 3, 4, 5, 6 };
    Cont::size_type sz = cont.size();
    cout << "size=" << sz << " content= ";
    for(Cont::const_iterator it = cont.begin(); it != cont.end(); ++it) 
        cout << *it << ' ';
    cout << '\n';
  }
  {
    using Cont = std::map<int,char>;
    Cont cont{ {1,'a'}, {2,'b'}, {3,'c'}, {4,'d'}, {5,'e'}, {6,'f'} };
    Cont::size_type sz = cont.size();
    cout << "size=" << sz << " content= ";
    for(Cont::const_iterator it = cont.begin(); it != cont.end(); ++it) 
        cout << *it << ' ';
    cout << '\n';
  }
}

Listing 24.12: Dies ist die Schablone für die Beispiellistings dieses Abschnitts zu vector.

Book listing lst-0710-book.cpp:

// https://godbolt.org/z/WK86eaz1x 
#include <vector>
#include <iostream>
using std::vector; using std::cout;
template<typename T>
std::ostream& operator<<(std::ostream&os, const vector<T>& data) {
    for(const auto &e : data) {
        os << e << ' ';
    }
    return os;
}
int main() {h
   // Beispielcode hier
}

Godbolt Listing lst-0710-godb.cpp, https://godbolt.org/z/WK86eaz1x:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WK86eaz1x 
#include <vector>
#include <iostream>
using std::vector; using std::cout;
template<typename T>
std::ostream& operator<<(std::ostream&os, const vector<T>& data) {
    for(const auto &e : data) {
        os << e << ' ';
    }
    return os;
}
int main() {h
   // Beispielcode hier
}

Listing 24.13: Der Standardkonstruktor initialisiert einen vector leer.

Book listing lst-0711-book.cpp:

// https://godbolt.org/z/7zMP5fo7c 
vector<int> dataA;
vector<int> dataB{};
vector<int> dataC = {};   // keine Zuweisung
cout << format("{} {} {}\n", dataA.size(), dataB.size(), dataC.size()); // 0 0 0

Godbolt Listing lst-0711-godb.cpp, https://godbolt.org/z/7zMP5fo7c:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7zMP5fo7c 
vector<int> dataA;
vector<int> dataB{};
vector<int> dataC = {};   // keine Zuweisung
cout << format("{} {} {}\n", dataA.size(), dataB.size(), dataC.size()); // 0 0 0

Listing 24.14: Sie kopieren einen »vector« mittels des Konstruktors oder implizit.

Book listing lst-0712-book.cpp:

// https://godbolt.org/z/cE6G1aErs 
auto zaehle(vector<int> arg) { return arg.size(); }
// …
vector input{1,2,3};           // vector<int>
vector outputA(input);         // Kopie
vector outputB = input;        // auch Kopie, keine Zuweisung
cout << zaehle(input) << '\n'; // Aufruf per Copy-by-Value

Godbolt Listing lst-0712-godb.cpp, https://godbolt.org/z/cE6G1aErs:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cE6G1aErs 
auto zaehle(vector<int> arg) { return arg.size(); }
// …
vector input{1,2,3};           // vector<int>
vector outputA(input);         // Kopie
vector outputB = input;        // auch Kopie, keine Zuweisung
cout << zaehle(input) << '\n'; // Aufruf per Copy-by-Value

Listing 24.15: Bei Rückgabewerten kann der Compiler auch oft verschieben.

Book listing lst-0713-book.cpp:

// https://godbolt.org/z/EK4e7Trv3 
#include <list>
#include <string>
#include <iterator>                      // make_move_iterator
using std::make_move_iterator; using std::string;
vector<int> erzeuge() { return vector<int>{8, 9, 10}; }
size_t zaehle(vector<int> d) { return d.size(); }
// …
vector input{1,2,3};
vector outputA(std::move(input));       // Verschiebung
vector outputB = std::move(input);      // auch Verschiebung, keine Zuweisung
vector data = erzeuge();                // Return-Value-Optimization
cout << zaehle(input) << '\n';          // Aufruf per Copy-by-Value
// elementweise aus einem anderen Container verschieben
std::list<string> quelle{ "a", "a", "a", "BB", "CC", "DD", "b", "b" };
auto von = quelle.begin();
std::advance(von, 3); // 3 vorwärts, bei list aber langsam
auto bis = von;
std::advance(bis, 3); // noch mal 3 vorwärts
vector ziel(make_move_iterator(von), make_move_iterator(bis));
// quelle ist nun {"a", "a", "a", "", "", "", "b", "b"}, ziel ist nun {"BB", "CC", "DD"}

Godbolt Listing lst-0713-godb.cpp, https://godbolt.org/z/EK4e7Trv3:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/EK4e7Trv3 
#include <list>
#include <string>
#include <iterator>                      // make_move_iterator
using std::make_move_iterator; using std::string;
vector<int> erzeuge() { return vector<int>{8, 9, 10}; }
size_t zaehle(vector<int> d) { return d.size(); }
// …
vector input{1,2,3};
vector outputA(std::move(input));       // Verschiebung
vector outputB = std::move(input);      // auch Verschiebung, keine Zuweisung
vector data = erzeuge();                // Return-Value-Optimization
cout << zaehle(input) << '\n';          // Aufruf per Copy-by-Value
// elementweise aus einem anderen Container verschieben
std::list<string> quelle{ "a", "a", "a", "BB", "CC", "DD", "b", "b" };
auto von = quelle.begin();
std::advance(von, 3); // 3 vorwärts, bei list aber langsam
auto bis = von;
std::advance(bis, 3); // noch mal 3 vorwärts
vector ziel(make_move_iterator(von), make_move_iterator(bis));
// quelle ist nun {"a", "a", "a", "", "", "", "b", "b"}, ziel ist nun {"BB", "CC", "DD"}

Listing 24.16: Mit einer Initialisierungsliste befüllen Sie einen vector vorab. Achten Sie auf die korrekten Typen in der Liste.

Book listing lst-0714-book.cpp:

// https://godbolt.org/z/4T7fjxdPa 
vector<int> prims{ 2,3,5,7,11 };
vector gerade{ 2,4,6,8,10 };
vector<int> soNicht{ 'a', 4.3, 8L };     //                                          (ERR)  "Narrowing" double nicht okay
vector<string> namen{ "sind", "nur" };   // konvertiert Argumente
vector schall{ "rauch", "qualm" };       // gefährlich: vector<const char[]>
vector nass{ "regen"s, "wasser"s };      // vector<string>
vector kalt{ "eis"sv, "pol"sv };         // vector<string_view>

Godbolt Listing lst-0714-godb.cpp, https://godbolt.org/z/4T7fjxdPa:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4T7fjxdPa 
vector<int> prims{ 2,3,5,7,11 };
vector gerade{ 2,4,6,8,10 };
vector<int> soNicht{ 'a', 4.3, 8L };     //                                          (ERR)  "Narrowing" double nicht okay
vector<string> namen{ "sind", "nur" };   // konvertiert Argumente
vector schall{ "rauch", "qualm" };       // gefährlich: vector<const char[]>
vector nass{ "regen"s, "wasser"s };      // vector<string>
vector kalt{ "eis"sv, "pol"sv };         // vector<string_view>

Listing 24.17: Kopieren Sie bei der Initialisierung Werte aus einem beliebigen anderen Container oder C-Array.

Book listing lst-0715-book.cpp:

// https://godbolt.org/z/foPadWsKs 
#include <deque>
#include <ranges>                       // C++20
// …
std::deque in{1,2,33,34,35,99};
vector dreissig(in.begin()+2, in.begin()+5);
for(auto &e : dreissig) {
    cout << e << ' ';
}
cout << '\n';
namespace vs = std::ranges::views;      // C++20
auto v = in | vs::drop(2) | vs::take(3);
vector otuz(v.begin(), v.end());
vector trente(std::from_range, in);     // C++23

Godbolt Listing lst-0715-godb.cpp, https://godbolt.org/z/foPadWsKs:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/foPadWsKs 
#include <deque>
#include <ranges>                       // C++20
// …
std::deque in{1,2,33,34,35,99};
vector dreissig(in.begin()+2, in.begin()+5);
for(auto &e : dreissig) {
    cout << e << ' ';
}
cout << '\n';
namespace vs = std::ranges::views;      // C++20
auto v = in | vs::drop(2) | vs::take(3);
vector otuz(v.begin(), v.end());
vector trente(std::from_range, in);     // C++23

Listing 24.18: Vorinitialisieren mit einer festen Anzahl von Werten gibt es (fast) nur bei »vector«.

Book listing lst-0716-book.cpp:

// https://godbolt.org/z/addobjfsK 
vector<int> zeros(10);        // 10 Nullen
vector<int> sechsen(10, 6);   // 10 Sechsen
vector<int> zehn{10};         //                                          (ERR)  Achtung! Nur eine 10
vector<int> zehnSechs{10, 6}; //                                          (ERR)  Achtung! Zwei Elemente 10 und 6

Godbolt Listing lst-0716-godb.cpp, https://godbolt.org/z/addobjfsK:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/addobjfsK 
vector<int> zeros(10);        // 10 Nullen
vector<int> sechsen(10, 6);   // 10 Sechsen
vector<int> zehn{10};         //                                          (ERR)  Achtung! Nur eine 10
vector<int> zehnSechs{10, 6}; //                                          (ERR)  Achtung! Zwei Elemente 10 und 6

Listing 24.19: »vector« können Sie zuweisen oder mit »assign« später reinitialisieren.

Book listing lst-0717-book.cpp:

// https://godbolt.org/z/Yb4jEdaKj 
vector<int> von{ 2,3,4 };
vector<int> nach{};
nach = von;                         // Zuweisung mit operator=, nun beide gleich

vector<int> abfluss{};
abfluss = std::move(von);           // Verschieben, nun ist 'von' leer
vector<int> v;
v.assign(4, 100);                   // v ist nun {100, 100, 100, 100}
v.assign(nach.begin(), nach.end()); // v ist nun {2,3,4}
int z[] = { 10, 20, 30, 40 };
v.assign(z+1, z+4);                 // v ist nun {20, 30, 40}

Godbolt Listing lst-0717-godb.cpp, https://godbolt.org/z/Yb4jEdaKj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Yb4jEdaKj 
vector<int> von{ 2,3,4 };
vector<int> nach{};
nach = von;                         // Zuweisung mit operator=, nun beide gleich

vector<int> abfluss{};
abfluss = std::move(von);           // Verschieben, nun ist 'von' leer
vector<int> v;
v.assign(4, 100);                   // v ist nun {100, 100, 100, 100}
v.assign(nach.begin(), nach.end()); // v ist nun {2,3,4}
int z[] = { 10, 20, 30, 40 };
v.assign(z+1, z+4);                 // v ist nun {20, 30, 40}

Listing 24.20: Mit »begin«, »end« und deren Verwandten erhalten Sie Iteratoren.

Book listing lst-0718-book.cpp:

// https://godbolt.org/z/6ahzhdjva 
vector vokale { 'A', 'e', 'i', 'o', 'u' };
const vector gerade { '0', '2', '4', '6', '8' };
auto it1 = vokale.begin();                 // vector<char>::iterator
*it1 = 'a';                                // '*it1' liefert 'char&' zurück
auto it2 = gerade.begin();                 // vector<char>::const_iterator
auto it3 = vokale.cbegin();                // erzwingt const_iterator
*i2 = '9'; *i3 = 'x';                      //                                          (ERR)  'const char&' ist nicht veränderbar
for(auto it=vokale.cbegin()+1; it!=vokale.cend(); ++it)
    { cout << *it; } cout << '\n';         // Ausgabe: eiou
for(auto it=vokale.crbegin()+1; it!=vokale.crend(); ++it) // ++ trotz reverse!
    { cout << *it; } cout << '\n';         // Ausgabe: oiea

Godbolt Listing lst-0718-godb.cpp, https://godbolt.org/z/6ahzhdjva:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6ahzhdjva 
vector vokale { 'A', 'e', 'i', 'o', 'u' };
const vector gerade { '0', '2', '4', '6', '8' };
auto it1 = vokale.begin();                 // vector<char>::iterator
*it1 = 'a';                                // '*it1' liefert 'char&' zurück
auto it2 = gerade.begin();                 // vector<char>::const_iterator
auto it3 = vokale.cbegin();                // erzwingt const_iterator
*i2 = '9'; *i3 = 'x';                      //                                          (ERR)  'const char&' ist nicht veränderbar
for(auto it=vokale.cbegin()+1; it!=vokale.cend(); ++it)
    { cout << *it; } cout << '\n';         // Ausgabe: eiou
for(auto it=vokale.crbegin()+1; it!=vokale.crend(); ++it) // ++ trotz reverse!
    { cout << *it; } cout << '\n';         // Ausgabe: oiea

Listing 24.21: Mit »vector«-Iteratoren können Sie wahlfrei rechnen.

Book listing lst-0719-book.cpp:

// https://godbolt.org/z/vMa8bPaob 
#include <vector>
#include <iostream>
#include <algorithm>                // ranges::sort
using std::vector; using std::cout;
double median(vector<int> daten) {  // kopiert
    std::ranges::sort(daten);       // C++20, sonst std::sort()
    auto it = daten.begin();
    auto sz = daten.size();
    if(sz==0) return 0;             // Sonderfall
    // Median ermitteln:
    auto m = (it+sz/2);             // ungefähr die Mitte
    if(sz%2 != 0) {                 // ungerade Anzahl Elemente
        return *m;
    } else {                        // gerade Anzahl Elemente
        return double(*m + *(m-1)) / 2;
    }
}
int main() {
    vector daten1 { 12, 22, 34, 10, 1, 99, 33 };
    cout << median(daten1) << '\n'; // 22
    vector daten2 { 30, 2, 80, 99, 31, 3 };
    cout << median(daten2) << '\n'; // 30.5
}

Godbolt Listing lst-0719-godb.cpp, https://godbolt.org/z/vMa8bPaob:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vMa8bPaob 
#include <vector>
#include <iostream>
#include <algorithm>                // ranges::sort
using std::vector; using std::cout;
double median(vector<int> daten) {  // kopiert
    std::ranges::sort(daten);       // C++20, sonst std::sort()
    auto it = daten.begin();
    auto sz = daten.size();
    if(sz==0) return 0;             // Sonderfall
    // Median ermitteln:
    auto m = (it+sz/2);             // ungefähr die Mitte
    if(sz%2 != 0) {                 // ungerade Anzahl Elemente
        return *m;
    } else {                        // gerade Anzahl Elemente
        return double(*m + *(m-1)) / 2;
    }
}
int main() {
    vector daten1 { 12, 22, 34, 10, 1, 99, 33 };
    cout << median(daten1) << '\n'; // 22
    vector daten2 { 30, 2, 80, 99, 31, 3 };
    cout << median(daten2) << '\n'; // 30.5
}

Listing 24.22: Der Normalfall ist Zugriff mit »[]«, weil Sie die Grenzen schon woanders überprüfen.

Book listing lst-0720-book.cpp:

// https://godbolt.org/z/aW3McGofx 
vector d{ 1, 2, 4, -1, 1, 2, -2 };
for(size_t idx=0; idx < d.size(); ) { // prüft vector-Grenze
    cout << d[idx] << ' ';            // zusätzliche Prüfung mit at nicht nötig
    idx += d[idx];                    // hier ebenso wenig
}
cout << '\n';
// Ausgabe: 1 2 -1 4 -2 1 2

Godbolt Listing lst-0720-godb.cpp, https://godbolt.org/z/aW3McGofx:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/aW3McGofx 
vector d{ 1, 2, 4, -1, 1, 2, -2 };
for(size_t idx=0; idx < d.size(); ) { // prüft vector-Grenze
    cout << d[idx] << ' ';            // zusätzliche Prüfung mit at nicht nötig
    idx += d[idx];                    // hier ebenso wenig
}
cout << '\n';
// Ausgabe: 1 2 -1 4 -2 1 2

Listing 24.23: Konstanter Container liefert konstante Referenz zurück.

Book listing lst-0721-book.cpp:

// https://godbolt.org/z/jGx51caTj 
#include <vector>
#include <iostream>
void printAndMore(const std::vector<int>& data) { // by-const-ref
    std::cout << data[0] << std::endl;
    data[0] = 666;  //                                          (ERR)  geht nicht, weil 'const int&'
}
int main() {
    std::vector zahlen {1,2,3};
    printAndMore(zahlen);
}

Godbolt Listing lst-0721-godb.cpp, https://godbolt.org/z/jGx51caTj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jGx51caTj 
#include <vector>
#include <iostream>
void printAndMore(const std::vector<int>& data) { // by-const-ref
    std::cout << data[0] << std::endl;
    data[0] = 666;  //                                          (ERR)  geht nicht, weil 'const int&'
}
int main() {
    std::vector zahlen {1,2,3};
    printAndMore(zahlen);
}

Listing 24.24: insert verschiebt hier alle Elemente um eins nach hinten.

Book listing lst-0722-book.cpp:

// https://godbolt.org/z/YhYs3z5Ex 
vector<string> autos{ "Diesel", "Benzin", "Super", "Gas" };
cout << autos[1] << '\n';             // Ausgabe: Benzin
autos.insert(autos.begin(), "Strom"); // verschiebt alles um eins nach hinten
cout << autos[1] << '\n';             // Ausgabe: Diesel

Godbolt Listing lst-0722-godb.cpp, https://godbolt.org/z/YhYs3z5Ex:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YhYs3z5Ex 
vector<string> autos{ "Diesel", "Benzin", "Super", "Gas" };
cout << autos[1] << '\n';             // Ausgabe: Benzin
autos.insert(autos.begin(), "Strom"); // verschiebt alles um eins nach hinten
cout << autos[1] << '\n';             // Ausgabe: Diesel

Listing 24.25: Verwenden Sie data() als Schnittstelle zu C.

Book listing lst-0723-book.cpp:

// https://godbolt.org/z/evse4x8zK 
#include <vector>
#include <iostream>
#include <cstdio> // fopen, fclose, fwrite, fread, remove
using namespace std;
ostream& operator<<(ostream&os, const vector<int>&data) {
    for(auto &e : data) os << e << ' '; return os;
}
static const char* FILENAME = "nums.dat";
int main() {
  const vector nums{10,11,22,34};
  { // Schreiben
    auto out = fopen(FILENAME, "wb"); // Datei mit C zum Schreiben öffnen
    if(out==nullptr) {
        cerr << "Fehler beim Oeffnen\n"; return -1;
    }
    auto ok = fwrite(nums.data(), sizeof(int), nums.size(), out);
    if(ok!=nums.size()) {
        cerr << "Fehler beim Schreiben\n"; return -1;
    }
    fclose(out); // In C muss man explizit schließen. Ehrlich.
  }
  vector<int> gelesen{};
  { // Lesen
    auto in = fopen(FILENAME, "rb"); // Datei mit C zum Lesen öffnen
    if(in==nullptr) {
        cerr << "Fehler beim Oeffnen\n"; return -1;
    }
    const size_t sz = 4; // angenommen, wir wissen, wir lesen 4 Elemente …
    gelesen.resize(sz);  // Platz schaffen für zu lesende Daten
    auto ok = fread(gelesen.data(), sizeof(int), sz, in);
    if(ok!=sz) {
        cerr << "Fehler beim Lesen\n"; return -1;
    }
    fclose(in);
  }
  { // Vergleichen
    cout << nums << '\n';    // 10 11 22 34
    cout << gelesen << '\n'; // 10 11 22 34
  }
  if(remove(FILENAME) == -1) {
      cerr << "Warning: Fehler beim Loeschen\n";
  }
}

Godbolt Listing lst-0723-godb.cpp, https://godbolt.org/z/evse4x8zK:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/evse4x8zK 
#include <vector>
#include <iostream>
#include <cstdio> // fopen, fclose, fwrite, fread, remove
using namespace std;
ostream& operator<<(ostream&os, const vector<int>&data) {
    for(auto &e : data) os << e << ' '; return os;
}
static const char* FILENAME = "nums.dat";
int main() {
  const vector nums{10,11,22,34};
  { // Schreiben
    auto out = fopen(FILENAME, "wb"); // Datei mit C zum Schreiben öffnen
    if(out==nullptr) {
        cerr << "Fehler beim Oeffnen\n"; return -1;
    }
    auto ok = fwrite(nums.data(), sizeof(int), nums.size(), out);
    if(ok!=nums.size()) {
        cerr << "Fehler beim Schreiben\n"; return -1;
    }
    fclose(out); // In C muss man explizit schließen. Ehrlich.
  }
  vector<int> gelesen{};
  { // Lesen
    auto in = fopen(FILENAME, "rb"); // Datei mit C zum Lesen öffnen
    if(in==nullptr) {
        cerr << "Fehler beim Oeffnen\n"; return -1;
    }
    const size_t sz = 4; // angenommen, wir wissen, wir lesen 4 Elemente …
    gelesen.resize(sz);  // Platz schaffen für zu lesende Daten
    auto ok = fread(gelesen.data(), sizeof(int), sz, in);
    if(ok!=sz) {
        cerr << "Fehler beim Lesen\n"; return -1;
    }
    fclose(in);
  }
  { // Vergleichen
    cout << nums << '\n';    // 10 11 22 34
    cout << gelesen << '\n'; // 10 11 22 34
  }
  if(remove(FILENAME) == -1) {
      cerr << "Warning: Fehler beim Loeschen\n";
  }
}

Listing 24.26: So verwenden Sie span.

Book listing lst-0728-book.cpp:

// https://godbolt.org/z/h7jf4KM1q 
#include <vector>
#include <span>
#include <iostream>
using namespace std;
int sum(span<const int> bereich) { // C++20: span
   int sum = 0;
   for(auto e : bereich) {         // algorithm wäre besser …
    sum += e;
   }
   return sum;
}
int main() {
    vector data {1,2,3,4,5};
    cout << sum(data) << "\n";            // implizit Container zu span
    auto [b, e, sz] = make_tuple(begin(data), end(data), size(data));
    cout << sum(span{b,   sz-1}) << "\n"; // 1..4 (Iter, size)
    cout << sum(span{b+1, sz-1}) << "\n"; // 2..5 (Iter, size)
    cout << sum(span{b,   e-2}) << "\n";  // 1..3 (Iter, Iter)
    cout << sum(span{b+1, e-1}) << "\n";  // 2..4 (Iter, Iter)
    cout << sum(span{b+2, e  }) << "\n";  // 3..5 (Iter, Iter)
    return 0;
}

Godbolt Listing lst-0728-godb.cpp, https://godbolt.org/z/h7jf4KM1q:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h7jf4KM1q 
#include <vector>
#include <span>
#include <iostream>
using namespace std;
int sum(span<const int> bereich) { // C++20: span
   int sum = 0;
   for(auto e : bereich) {         // algorithm wäre besser …
    sum += e;
   }
   return sum;
}
int main() {
    vector data {1,2,3,4,5};
    cout << sum(data) << "\n";            // implizit Container zu span
    auto [b, e, sz] = make_tuple(begin(data), end(data), size(data));
    cout << sum(span{b,   sz-1}) << "\n"; // 1..4 (Iter, size)
    cout << sum(span{b+1, sz-1}) << "\n"; // 2..5 (Iter, size)
    cout << sum(span{b,   e-2}) << "\n";  // 1..3 (Iter, Iter)
    cout << sum(span{b+1, e-1}) << "\n";  // 2..4 (Iter, Iter)
    cout << sum(span{b+2, e  }) << "\n";  // 3..5 (Iter, Iter)
    return 0;
}

Listing 24.27: Dies sind span mit fester Größe.

Book listing lst-0731-book.cpp:

// https://godbolt.org/z/a3qqr1YPM 
int car[5]  {1,2,3,4,5};
span span_1 = car;          // direkt aus einem C-Array
array arr   {1,2,3,4,5};
span span_2 {arr};          // direkt aus einem std::array
vector vec  {1,2,3,4,5};
span<int,3> span_3 {vec};   // mit 'Extent' aus einem std::vector

Godbolt Listing lst-0731-godb.cpp, https://godbolt.org/z/a3qqr1YPM:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a3qqr1YPM 
int car[5]  {1,2,3,4,5};
span span_1 = car;          // direkt aus einem C-Array
array arr   {1,2,3,4,5};
span span_2 {arr};          // direkt aus einem std::array
vector vec  {1,2,3,4,5};
span<int,3> span_3 {vec};   // mit 'Extent' aus einem std::vector

Listing 24.28: Durch eine »span« kann man auch schreiben.

Book listing lst-0733-book.cpp:

// https://godbolt.org/z/6Ez5GdozG 
#include <vector>
#include <span>
#include <iostream>
using namespace std;
void inc(span<int> span) {
   for(auto& e :span) {  // Referenz
     e += 1;             // schreiben
   }
}
int main() {
    vector data {1,2,3,4,5};
    span ganz{data};              //    1,2,3,4,5
    inc(ganz.first(3));           // -> 2,3,4,4,5
    inc(ganz.last(3));            // -> 2,3,5,5,6
    inc(ganz.last(4).first(3));   // -> 2,4,6,6,6
    inc(ganz.subspan(1,3));       // -> 2,5,7,7,6
    for(auto i: ganz) cout << i << ' '; cout << '\n'; // Ausgabe: 2 5 7 7 6
    return 0;
}

Godbolt Listing lst-0733-godb.cpp, https://godbolt.org/z/6Ez5GdozG:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6Ez5GdozG 
#include <vector>
#include <span>
#include <iostream>
using namespace std;
void inc(span<int> span) {
   for(auto& e :span) {  // Referenz
     e += 1;             // schreiben
   }
}
int main() {
    vector data {1,2,3,4,5};
    span ganz{data};              //    1,2,3,4,5
    inc(ganz.first(3));           // -> 2,3,4,4,5
    inc(ganz.last(3));            // -> 2,3,5,5,6
    inc(ganz.last(4).first(3));   // -> 2,4,6,6,6
    inc(ganz.subspan(1,3));       // -> 2,5,7,7,6
    for(auto i: ganz) cout << i << ' '; cout << '\n'; // Ausgabe: 2 5 7 7 6
    return 0;
}

Listing 24.29: So funktioniert die in C++23 hinzugekommene »mdspan«.

Book listing lst-0734-book.cpp:

// https://godbolt.org/z/n8jn7v5vb 
#include <mdspan>
#include <iostream>
#include <vector>
using namespace std;
int main() {
    // 1D: 12 Elemente
    vector v{1,2,3,4,5,6,7,8,9,10,11,12};
    // 2D: als 2 Zeilen mit je 6 ints
    auto ms2 = mdspan(v.data(), 2, 6);
    // 3D: als Quader mit 2 Ebenen, 3 Reihen, 2 Spalten
    auto ms3 = mdspan(v.data(), 2, 3, 2);
    // via 2D-Ansicht schreiben
    for (auto i = 0; i != ms2.extent(0); ++i)
      for (auto j = 0; j != ms2.extent(1); ++j)
        ms2[i, j] = i * 100 + j;  // schreiben via mehrdimensionalen Index
    // via 3D-Ansicht lesen
    for (auto i = 0; i != ms3.extent(0); ++i) {
      cout << "Ebene " << i << ":\n";
      for (auto j = 0; j != ms3.extent(1); ++j) {
        for (auto k = 0; k != ms3.extent(2); ++k)
          cout << " " << ms3[i, j, k];  // lesen via mehrdimensionalen Index
        cout << '\n';
      }
    }
    // Ausgabe: Ebene 0: 0 1, 2 3, 4 5, Ebene 1: 100 101, 102 103, 104 105
}

Godbolt Listing lst-0734-godb.cpp, https://godbolt.org/z/n8jn7v5vb:

//#(compile) c++; compiler:gsnapshot; options:"-std=c++23"; libs:-
// https://godbolt.org/z/n8jn7v5vb 
#include <mdspan>
#include <iostream>
#include <vector>
using namespace std;
int main() {
    // 1D: 12 Elemente
    vector v{1,2,3,4,5,6,7,8,9,10,11,12};
    // 2D: als 2 Zeilen mit je 6 ints
    auto ms2 = mdspan(v.data(), 2, 6);
    // 3D: als Quader mit 2 Ebenen, 3 Reihen, 2 Spalten
    auto ms3 = mdspan(v.data(), 2, 3, 2);
    // via 2D-Ansicht schreiben
    for (auto i = 0; i != ms2.extent(0); ++i)
      for (auto j = 0; j != ms2.extent(1); ++j)
        ms2[i, j] = i * 100 + j;  // schreiben via mehrdimensionalen Index
    // via 3D-Ansicht lesen
    for (auto i = 0; i != ms3.extent(0); ++i) {
      cout << "Ebene " << i << ":\n";
      for (auto j = 0; j != ms3.extent(1); ++j) {
        for (auto k = 0; k != ms3.extent(2); ++k)
          cout << " " << ms3[i, j, k];  // lesen via mehrdimensionalen Index
        cout << '\n';
      }
    }
    // Ausgabe: Ebene 0: 0 1, 2 3, 4 5, Ebene 1: 100 101, 102 103, 104 105
}

Listing 24.30: Typischerweise fügen Sie am Ende bei vector an.

Book listing lst-0735-book.cpp:

// https://godbolt.org/z/P6MrKfaj9 
#include <vector>
#include <string>
struct Praesident {
  std::string name_; int jahr_;
  Praesident(std::string name,  int jahr)    // name ist by Value
    : name_{std::move(name)}, jahr_{jahr}    // move spart hier eine weitere Kopie
    { }
};
int main() {
    using namespace std; // Stringliterale ermöglichen
    vector<Praesident> praesidenten{};
    praesidenten.emplace_back("Heuss"s, 1949);
    praesidenten.emplace_back("Luebke"s, 1959);
    praesidenten.emplace_back("Heinemann"s, 1969);
    // …
    vector<int> v{};
    v.reserve(100);
    for(int idx = 0; idx < 100; ++idx)
        v.push_back(idx);
    // …
}

Godbolt Listing lst-0735-godb.cpp, https://godbolt.org/z/P6MrKfaj9:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/P6MrKfaj9 
#include <vector>
#include <string>
struct Praesident {
  std::string name_; int jahr_;
  Praesident(std::string name,  int jahr)    // name ist by Value
    : name_{std::move(name)}, jahr_{jahr}    // move spart hier eine weitere Kopie
    { }
};
int main() {
    using namespace std; // Stringliterale ermöglichen
    vector<Praesident> praesidenten{};
    praesidenten.emplace_back("Heuss"s, 1949);
    praesidenten.emplace_back("Luebke"s, 1959);
    praesidenten.emplace_back("Heinemann"s, 1969);
    // …
    vector<int> v{};
    v.reserve(100);
    for(int idx = 0; idx < 100; ++idx)
        v.push_back(idx);
    // …
}

GodboltId:6836bdczd

Book listing lst-0738-book.cpp:

// https://godbolt.org/z/6836bdczd 
std::vector v{ 1, 2, 3, 4, 5, 6 };
for(auto it=v.begin(); it!=v.end(); ++it) {
  it = v.erase(it);
}
// Hier ist v: { 2, 4, 6 }

Godbolt Listing lst-0738-godb.cpp, https://godbolt.org/z/6836bdczd:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6836bdczd 
std::vector v{ 1, 2, 3, 4, 5, 6 };
for(auto it=v.begin(); it!=v.end(); ++it) {
  it = v.erase(it);
}
// Hier ist v: { 2, 4, 6 }

Listing 24.31: erase mit zwei Parametern löscht einen ganzen Bereich.

Book listing lst-0739-book.cpp:

// https://godbolt.org/z/fe8bev9Y9 
std::vector v{ 1, 2, 3, 4, 5, 6 };
v.erase(v.begin()+2, v.begin()+5); // v ist nun {1, 6}
v.erase(v.begin(), v.end());       // löscht den Rest

Godbolt Listing lst-0739-godb.cpp, https://godbolt.org/z/fe8bev9Y9:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fe8bev9Y9 
std::vector v{ 1, 2, 3, 4, 5, 6 };
v.erase(v.begin()+2, v.begin()+5); // v ist nun {1, 6}
v.erase(v.begin(), v.end());       // löscht den Rest

Listing 24.32: Operationen rund um Größe und Kapazität von »vector«.

Book listing lst-0741-book.cpp:

// https://godbolt.org/z/xYsherrjs 
#include <vector>
#include <iostream>
#include <format> // C++20
using namespace std;
ostream& operator<<(ostream&os, const vector<int> &vec) {
  for(auto &elem : vec) { os << elem << ' '; } return os;
}
int main() {
  vector<int> data {};     // erzeugt einen leeren vector
  data.reserve(3);         // Platz für 3 Elemente
  cout << format("{}/{}\n", data.size(), data.capacity()); // 0/3
  data.push_back(111);     // ein Element hinzufügen
  data.resize(3);          // Größe verändern; hier fügt es neue Elemente an
  data.push_back(999);     // noch ein Element hinzufügen
  cout << format("{}/{}\n", data.size(), data.capacity()); // 4/6
  cout << data << '\n';    // 111, 0, 0, 999
  data.push_back(333);     // noch ein Element anfügen
  cout << data << '\n';    // 111, 0, 0, 999, 333
  data.reserve(1);         // nichts passiert, denn capacity() > 1
  data.resize(3);          // schrumpfen; Elemente werden entfernt
  cout << data << '\n';    // 111, 0, 0
  cout << format("{}/{}\n", data.size(), data.capacity()); // 3/6
  data.resize(6, 44);      // noch mal vergrößern, mit 44en auffüllen
  cout << data << '\n';    // 111, 0, 0, 44, 44, 44
}

Godbolt Listing lst-0741-godb.cpp, https://godbolt.org/z/xYsherrjs:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xYsherrjs 
#include <vector>
#include <iostream>
#include <format> // C++20
using namespace std;
ostream& operator<<(ostream&os, const vector<int> &vec) {
  for(auto &elem : vec) { os << elem << ' '; } return os;
}
int main() {
  vector<int> data {};     // erzeugt einen leeren vector
  data.reserve(3);         // Platz für 3 Elemente
  cout << format("{}/{}\n", data.size(), data.capacity()); // 0/3
  data.push_back(111);     // ein Element hinzufügen
  data.resize(3);          // Größe verändern; hier fügt es neue Elemente an
  data.push_back(999);     // noch ein Element hinzufügen
  cout << format("{}/{}\n", data.size(), data.capacity()); // 4/6
  cout << data << '\n';    // 111, 0, 0, 999
  data.push_back(333);     // noch ein Element anfügen
  cout << data << '\n';    // 111, 0, 0, 999, 333
  data.reserve(1);         // nichts passiert, denn capacity() > 1
  data.resize(3);          // schrumpfen; Elemente werden entfernt
  cout << data << '\n';    // 111, 0, 0
  cout << format("{}/{}\n", data.size(), data.capacity()); // 3/6
  data.resize(6, 44);      // noch mal vergrößern, mit 44en auffüllen
  cout << data << '\n';    // 111, 0, 0, 44, 44, 44
}

GodboltId:Y1W8WfxYn

Book listing lst-0742-book.cpp:

// https://godbolt.org/z/Y1W8WfxYn 
#include <array>
void berechne(const std::array<int,4>& data) { /* ... */ }
void berechne(const std::array<int,5>& data) { /* ... */ }

Godbolt Listing lst-0742-godb.cpp, https://godbolt.org/z/Y1W8WfxYn:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Y1W8WfxYn 
#include <array>
void berechne(const std::array<int,4>& data) { /* ... */ }
void berechne(const std::array<int,5>& data) { /* ... */ }

Listing 24.33: Unterschiedliche »arrays« als Parameter benötigen Templateprogrammierung.

Book listing lst-0743-book.cpp:

// https://godbolt.org/z/nqbKT9GEa 
#include <array>
#include <numeric> // accumulate
#include <iostream>
template<size_t SZ>
int sumSz(const std::array<int,SZ>& data) {
    int result = 0;
    for(auto i=0uz; i<SZ; ++i)           // uz ist das Suffix für size_t seit C++23
        result += data[i];
    return result;
}
template<typename Elem, size_t SZ>
Elem sumElem(const std::array<Elem,SZ>& data) {
    Elem result {0};
    for(auto i=0uz; i<SZ; ++i)
        result += data[i];
    return result;
}
// C++20-Concept input_iterator, sonst typename
template<std::input_iterator It>
int sumIt(It begin, It end) {
    return std::accumulate(begin, end, 0);
}
int sumAuto(std::input_iterator auto begin, std::input_iterator auto end) {
    return std::accumulate(begin, end, 0);
}
// abgekürztes funktionstemplate mit auto
int main() {
   using namespace std;
   array<int,4> a4 { 1, 2, 5, 8 };
   cout << sumSz<4>(a4) << '\n';                  // Ausgabe: 16
   array<int,5> a5 { 1, -5, 3, 7, 2 };
   cout << sumElem(a5) << '\n';                   // Ausgabe: 8
   array<int,6> a6 { 1,2,3, 4,5,6 };
   cout << sumIt(a6.begin(), a6.end()) << '\n';   // Ausgabe: 21
   array a7 { 1,2,3, 4,5,6, 7 };                  // array<int,7>
   cout << sumIt(a7.begin(), a7.end()) << '\n';   // Ausgabe: 28
   cout << sumAuto(a7.begin(), a7.end()) << '\n'; // Ausgabe: 28
}

Godbolt Listing lst-0743-godb.cpp, https://godbolt.org/z/nqbKT9GEa:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/nqbKT9GEa 
#include <array>
#include <numeric> // accumulate
#include <iostream>
template<size_t SZ>
int sumSz(const std::array<int,SZ>& data) {
    int result = 0;
    for(auto i=0uz; i<SZ; ++i)           // uz ist das Suffix für size_t seit C++23
        result += data[i];
    return result;
}
template<typename Elem, size_t SZ>
Elem sumElem(const std::array<Elem,SZ>& data) {
    Elem result {0};
    for(auto i=0uz; i<SZ; ++i)
        result += data[i];
    return result;
}
// C++20-Concept input_iterator, sonst typename
template<std::input_iterator It>
int sumIt(It begin, It end) {
    return std::accumulate(begin, end, 0);
}
int sumAuto(std::input_iterator auto begin, std::input_iterator auto end) {
    return std::accumulate(begin, end, 0);
}
// abgekürztes funktionstemplate mit auto
int main() {
   using namespace std;
   array<int,4> a4 { 1, 2, 5, 8 };
   cout << sumSz<4>(a4) << '\n';                  // Ausgabe: 16
   array<int,5> a5 { 1, -5, 3, 7, 2 };
   cout << sumElem(a5) << '\n';                   // Ausgabe: 8
   array<int,6> a6 { 1,2,3, 4,5,6 };
   cout << sumIt(a6.begin(), a6.end()) << '\n';   // Ausgabe: 21
   array a7 { 1,2,3, 4,5,6, 7 };                  // array<int,7>
   cout << sumIt(a7.begin(), a7.end()) << '\n';   // Ausgabe: 28
   cout << sumAuto(a7.begin(), a7.end()) << '\n'; // Ausgabe: 28
}

Listing 24.34: Schablone für die Beispiellistings dieses Abschnitts zu »array«

Book listing lst-0744-book.cpp:

// https://godbolt.org/z/PrM4fGcWo 
#include <array>
#include <iostream>
using std::array; using std::cout;
template<typename Elem, size_t SZ>
std::ostream& operator<<(std::ostream&os, const array<Elem,SZ>&data) {
    for(auto &e : data) {
        os << e << ' ';
    }
    return os;
}
int main() {
   // Beispielcode hier
}

Godbolt Listing lst-0744-godb.cpp, https://godbolt.org/z/PrM4fGcWo:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/PrM4fGcWo 
#include <array>
#include <iostream>
using std::array; using std::cout;
template<typename Elem, size_t SZ>
std::ostream& operator<<(std::ostream&os, const array<Elem,SZ>&data) {
    for(auto &e : data) {
        os << e << ' ';
    }
    return os;
}
int main() {
   // Beispielcode hier
}

Listing 24.36: »array« unterstützt »get« von »tuple«.

Book listing lst-0745-book.cpp:

// https://godbolt.org/z/KrbTrx1aG 
array<int,5> data{ 10, 11, 12, 13, 14};
cout << std::get<2>(data) << '\n'; // 12

Godbolt Listing lst-0745-godb.cpp, https://godbolt.org/z/KrbTrx1aG:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KrbTrx1aG 
array<int,5> data{ 10, 11, 12, 13, 14};
cout << std::get<2>(data) << '\n'; // 12

Listing 24.37: Ein Array unterstützt strukturiertes Binden.

Book listing lst-0746-book.cpp:

// https://godbolt.org/z/h6nrPYWfM 
#include <array>
#include <iostream>
int main() {
    std::array ports { 80, 443  };          // array<int>
    auto [ http, https ] = ports;           // deklariert Variablen und bindet sie
    std::cout << http << " " << https << "\n";
    auto const& [ rhttp, rhttps ] = ports;  // Referenz und const sind möglich
    std::cout << rhttp << " " << rhttps << "\n";
}

Godbolt Listing lst-0746-godb.cpp, https://godbolt.org/z/h6nrPYWfM:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h6nrPYWfM 
#include <array>
#include <iostream>
int main() {
    std::array ports { 80, 443  };          // array<int>
    auto [ http, https ] = ports;           // deklariert Variablen und bindet sie
    std::cout << http << " " << https << "\n";
    auto const& [ rhttp, rhttps ] = ports;  // Referenz und const sind möglich
    std::cout << rhttp << " " << rhttps << "\n";
}

Listing 24.38: Arrays können Sie lexikografisch vergleichen.

Book listing lst-0747-book.cpp:

// https://godbolt.org/z/n16WYf58h 
template<typename E, size_t SZ>
void alle(const array<int,4>& a, const array<int,4>& b) { // absichtlich array& 
                                                          // als Argumente
     cout << "{"<<a<<"} verglichen mit {"<<b<<"} ist "
       << (a < b ? "<, " : "")
       << (a <= b ? "<=, " : "")
       << (a > b ? ">, " : "")
       << (a >= b ? ">=, " : "")
       << (a == b ? "==, " : "")
       << (a != b ? "!=, " : "")
       << '\n';
}
int main() {
    array a{10,10,10,10};
    array b{20, 5, 5, 5};
    array c{10,10,5,21};
    array d{10,10,10,10};
    cout << (a < b ? "kleiner\n" : "nicht kleiner\n"); // "kleiner", weil 10 < 20
    cout << (a < c ? "kleiner\n" : "nicht kleiner\n"); // "nicht …", weil nicht 10 < 5
    cout << (a == d ? "gleich\n" : "nicht gleich\n");  // "gleich", weil alles 10
    for(auto &x : {a,b,c}) {
        for(auto &y : {a,b,c}) {
            alle(x,y);
        }
    }
}

Godbolt Listing lst-0747-godb.cpp, https://godbolt.org/z/n16WYf58h:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/n16WYf58h 
template<typename E, size_t SZ>
void alle(const array<int,4>& a, const array<int,4>& b) { // absichtlich array& 
                                                          // als Argumente
     cout << "{"<<a<<"} verglichen mit {"<<b<<"} ist "
       << (a < b ? "<, " : "")
       << (a <= b ? "<=, " : "")
       << (a > b ? ">, " : "")
       << (a >= b ? ">=, " : "")
       << (a == b ? "==, " : "")
       << (a != b ? "!=, " : "")
       << '\n';
}
int main() {
    array a{10,10,10,10};
    array b{20, 5, 5, 5};
    array c{10,10,5,21};
    array d{10,10,10,10};
    cout << (a < b ? "kleiner\n" : "nicht kleiner\n"); // "kleiner", weil 10 < 20
    cout << (a < c ? "kleiner\n" : "nicht kleiner\n"); // "nicht …", weil nicht 10 < 5
    cout << (a == d ? "gleich\n" : "nicht gleich\n");  // "gleich", weil alles 10
    for(auto &x : {a,b,c}) {
        for(auto &y : {a,b,c}) {
            alle(x,y);
        }
    }
}

Listing 24.39: Wir entfernen paarweise vorne und hinten und vergleichen.

Book listing lst-0748-book.cpp:

// https://godbolt.org/z/rc1f3Yd9r 
#include <deque>
#include <iostream>
#include <string>
#include <cctype>   // toupper
#include <iomanip>  // boolalpha
using namespace std;
bool isPalindrome(string_view word) {
    // von beiden Enden gleichzeitig prüfen
    deque<char> deq{};
    for(char ch : word) {
        deq.push_back(toupper(ch));   // Großbuchstaben
    }
    auto ok = true;
    while(deq.size()>1 && ok) {
       if(deq.front() != deq.back()) {
           ok = false;
       }
       deq.pop_front();               // Hallo deque!
       deq.pop_back();
    }
    return ok;
}
int main() {
    cout << boolalpha; // Drucke 'true' und 'false' statt '1' und '0'
    cout << isPalindrome("Abrakadabra") << '\n';   // false
    cout << isPalindrome("Kajak") << '\n';         // true
    cout << isPalindrome("Lagerregal") << '\n';    // true
    cout << isPalindrome("Reliefpfeiler") << '\n'; // true
    cout << isPalindrome("Rentner") << '\n';       // true
    cout << isPalindrome("") << '\n';              // true
}

Godbolt Listing lst-0748-godb.cpp, https://godbolt.org/z/rc1f3Yd9r:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rc1f3Yd9r 
#include <deque>
#include <iostream>
#include <string>
#include <cctype>   // toupper
#include <iomanip>  // boolalpha
using namespace std;
bool isPalindrome(string_view word) {
    // von beiden Enden gleichzeitig prüfen
    deque<char> deq{};
    for(char ch : word) {
        deq.push_back(toupper(ch));   // Großbuchstaben
    }
    auto ok = true;
    while(deq.size()>1 && ok) {
       if(deq.front() != deq.back()) {
           ok = false;
       }
       deq.pop_front();               // Hallo deque!
       deq.pop_back();
    }
    return ok;
}
int main() {
    cout << boolalpha; // Drucke 'true' und 'false' statt '1' und '0'
    cout << isPalindrome("Abrakadabra") << '\n';   // false
    cout << isPalindrome("Kajak") << '\n';         // true
    cout << isPalindrome("Lagerregal") << '\n';    // true
    cout << isPalindrome("Reliefpfeiler") << '\n'; // true
    cout << isPalindrome("Rentner") << '\n';       // true
    cout << isPalindrome("") << '\n';              // true
}

Listing 24.40: Was die »deque« so alles kann!

Book listing lst-0750-book.cpp:

// https://godbolt.org/z/7P1Ef7jj4 
#include <deque>
#include <iostream>
#include <iterator>  // ostream_iterator
#include <algorithm> // copy
using namespace std;
ostream& operator<<=(ostream& os, int val) { return os<<val<<'\n'; }
int main() {
    deque d{ 4, 6 };           // deque<int> mit Elementen erzeugen
    // Einfügen
    d.push_front(3);           // am Kopf: effizient
    d.insert(d.begin()+2, 5);  // mittendrin: langsam
    d.push_back(7);            // am Ende: effizient
    // Zugriff
    cout <<= d.front();        // vom Kopf: effizient
    cout <<= d[3];             // mittendrin: effizient
    cout <<= d.back();         // vom Ende: effizient
    // Größe
    cout <<= d.size();         // Größe lesen
    d.resize(4);               // Größe kappen (oder erweitern)
    // Iteratoren
    copy(d.begin(), d.end(), ostream_iterator<int>(cout, " "));
    cout << '\n';              // Ausgabe: 3 4 5 6
    // Entfernen
    d.pop_front();             // am Kopf: effizient
    d.erase(d.begin()+1);      // mittendrin: langsam
    d.pop_back();              // am Ende: effizient
    d.clear();                 // leeren
}

Godbolt Listing lst-0750-godb.cpp, https://godbolt.org/z/7P1Ef7jj4:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7P1Ef7jj4 
#include <deque>
#include <iostream>
#include <iterator>  // ostream_iterator
#include <algorithm> // copy
using namespace std;
ostream& operator<<=(ostream& os, int val) { return os<<val<<'\n'; }
int main() {
    deque d{ 4, 6 };           // deque<int> mit Elementen erzeugen
    // Einfügen
    d.push_front(3);           // am Kopf: effizient
    d.insert(d.begin()+2, 5);  // mittendrin: langsam
    d.push_back(7);            // am Ende: effizient
    // Zugriff
    cout <<= d.front();        // vom Kopf: effizient
    cout <<= d[3];             // mittendrin: effizient
    cout <<= d.back();         // vom Ende: effizient
    // Größe
    cout <<= d.size();         // Größe lesen
    d.resize(4);               // Größe kappen (oder erweitern)
    // Iteratoren
    copy(d.begin(), d.end(), ostream_iterator<int>(cout, " "));
    cout << '\n';              // Ausgabe: 3 4 5 6
    // Entfernen
    d.pop_front();             // am Kopf: effizient
    d.erase(d.begin()+1);      // mittendrin: langsam
    d.pop_back();              // am Ende: effizient
    d.clear();                 // leeren
}

Listing 24.41: »splice« ist die Spezialität von »list« und verbindet zwei Listen effizient.

Book listing lst-0751-book.cpp:

// https://godbolt.org/z/so5Gebb4M 
#include <list>
#include <iostream>
using std::list; using std::cout; using std::ostream;

ostream& operator<<=(ostream&os, const list<int> &data)
    { for(auto &e:data) os<<e<<' '; return os<<'\n'; }

int main() {
    list numa { 1, 3, 5, 7, 9 };
    list numb { 2, 4, 6, 8 };
    auto wo = numa.end();
    numa.splice(wo, numb); // transferieren in O(1)
    cout <<= numa; // Ausgabe: 1 3 5 7 9 2 4 6 8
    cout <<= numb; // Ausgabe: (keine)
    numa.sort();   // sort als Methode, nicht aus <algorithm>
    cout <<= numa; // Ausgabe: 1 2 3 4 5 6 7 8 9
}

Godbolt Listing lst-0751-godb.cpp, https://godbolt.org/z/so5Gebb4M:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/so5Gebb4M 
#include <list>
#include <iostream>
using std::list; using std::cout; using std::ostream;

ostream& operator<<=(ostream&os, const list<int> &data)
    { for(auto &e:data) os<<e<<' '; return os<<'\n'; }

int main() {
    list numa { 1, 3, 5, 7, 9 };
    list numb { 2, 4, 6, 8 };
    auto wo = numa.end();
    numa.splice(wo, numb); // transferieren in O(1)
    cout <<= numa; // Ausgabe: 1 3 5 7 9 2 4 6 8
    cout <<= numb; // Ausgabe: (keine)
    numa.sort();   // sort als Methode, nicht aus <algorithm>
    cout <<= numa; // Ausgabe: 1 2 3 4 5 6 7 8 9
}

Listing 24.42: »before_begin« können Sie als Argument für »insert_after« nehmen.

Book listing lst-0752-book.cpp:

// https://godbolt.org/z/9b9fY4Mve 
#include <iostream>
#include <forward_list>
int main()     {
    std::forward_list mylist = {20, 30, 40, 50};
    mylist.insert_after(mylist.before_begin(), 11 );
    for (int& x: mylist) std::cout << ' ' << x; // Ausgabe: 11 20 30 40 50
    std::cout << '\n';
}

Godbolt Listing lst-0752-godb.cpp, https://godbolt.org/z/9b9fY4Mve:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9b9fY4Mve 
#include <iostream>
#include <forward_list>
int main()     {
    std::forward_list mylist = {20, 30, 40, 50};
    mylist.insert_after(mylist.before_begin(), 11 );
    for (int& x: mylist) std::cout << ' ' << x; // Ausgabe: 11 20 30 40 50
    std::cout << '\n';
}

Listing 24.43: »erase_after« kann einen Bereich von Elementen löschen.

Book listing lst-0753-book.cpp:

// https://godbolt.org/z/ajn3haEcY 
#include <forward_list>
#include <iostream>
#include <iterator> // next
using std::cout; using std::forward_list; using std::ostream;
ostream& operator<<=(ostream&os, const forward_list<int> &data)
    { for(auto &e:data) os<<e<<' '; return os<<'\n'; }

int main()     {
    forward_list zahlen {40, 50, 60, 70};
    cout <<= zahlen;                        // Ausgabe: 40 50 60 70
    zahlen.insert_after(zahlen.before_begin(), {10, 20, 30});
    cout <<= zahlen;                        // Ausgabe: 10 20 30 40 50 60 70
    auto wo = std::next(zahlen.begin(), 2); // zwei Elemente weiter
    auto bis = std::next(wo, 3);            // drei Elemente nach wo
    zahlen.erase_after(wo, bis);
    cout <<= zahlen;                        // Ausgabe: 10 20 30 60 70
}

Godbolt Listing lst-0753-godb.cpp, https://godbolt.org/z/ajn3haEcY:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ajn3haEcY 
#include <forward_list>
#include <iostream>
#include <iterator> // next
using std::cout; using std::forward_list; using std::ostream;
ostream& operator<<=(ostream&os, const forward_list<int> &data)
    { for(auto &e:data) os<<e<<' '; return os<<'\n'; }

int main()     {
    forward_list zahlen {40, 50, 60, 70};
    cout <<= zahlen;                        // Ausgabe: 40 50 60 70
    zahlen.insert_after(zahlen.before_begin(), {10, 20, 30});
    cout <<= zahlen;                        // Ausgabe: 10 20 30 40 50 60 70
    auto wo = std::next(zahlen.begin(), 2); // zwei Elemente weiter
    auto bis = std::next(wo, 3);            // drei Elemente nach wo
    zahlen.erase_after(wo, bis);
    cout <<= zahlen;                        // Ausgabe: 10 20 30 60 70
}

Listing 24.44: »splice_after« kann sehr effizient Listen zusammenfügen.

Book listing lst-0754-book.cpp:

// https://godbolt.org/z/Ka47W5Wjh 
#include <forward_list>
#include <iostream>
using std::cout; using std::forward_list; using std::ostream;

ostream& operator<<=(ostream&os, const forward_list<int> &data)
  { for(auto &e:data) os<<e<<' '; return os<<'\n'; }

int main() {
  {
    forward_list fw1 {10, 20, 30, 40};
    forward_list fw2 {5, 6, 7, 8};
    fw1.splice_after(fw1.begin(), fw2);  // transferiert alles
    cout <<= fw1;                 // Ausgabe: 10 5 6 7 8 20 30 40
    cout <<= fw2;                 // Ausgabe:
  }
  {
    forward_list fw1 {10, 20, 30, 40};
    forward_list fw2 {5, 6, 7, 8};
    // ein Element übrig:
    fw1.splice_after(fw1.begin(), fw2,fw2.begin(),fw2.end());
    cout <<= fw1;                 // Ausgabe: 10 6 7 8 20 30 40
    cout <<= fw2;                 // Ausgabe: 5
  }
}

Godbolt Listing lst-0754-godb.cpp, https://godbolt.org/z/Ka47W5Wjh:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Ka47W5Wjh 
#include <forward_list>
#include <iostream>
using std::cout; using std::forward_list; using std::ostream;

ostream& operator<<=(ostream&os, const forward_list<int> &data)
  { for(auto &e:data) os<<e<<' '; return os<<'\n'; }

int main() {
  {
    forward_list fw1 {10, 20, 30, 40};
    forward_list fw2 {5, 6, 7, 8};
    fw1.splice_after(fw1.begin(), fw2);  // transferiert alles
    cout <<= fw1;                 // Ausgabe: 10 5 6 7 8 20 30 40
    cout <<= fw2;                 // Ausgabe:
  }
  {
    forward_list fw1 {10, 20, 30, 40};
    forward_list fw2 {5, 6, 7, 8};
    // ein Element übrig:
    fw1.splice_after(fw1.begin(), fw2,fw2.begin(),fw2.end());
    cout <<= fw1;                 // Ausgabe: 10 6 7 8 20 30 40
    cout <<= fw2;                 // Ausgabe: 5
  }
}

Listing 24.45: Dies ist die Schablone für die Beispiellistings dieses Abschnitts zu »set«.

Book listing lst-0755-book.cpp:

// https://godbolt.org/z/h51oT7r3h 
#include <set>
#include <iostream>
using std::set; using std::cout;
template<typename Elem, typename Comp>
std::ostream& operator<<=(std::ostream&os, const set<Elem,Comp>&data) {
    for(auto &e : data) {
        os << e << ' ';
    }
    return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
   // Beispielcode hier
}

Godbolt Listing lst-0755-godb.cpp, https://godbolt.org/z/h51oT7r3h:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h51oT7r3h 
#include <set>
#include <iostream>
using std::set; using std::cout;
template<typename Elem, typename Comp>
std::ostream& operator<<=(std::ostream&os, const set<Elem,Comp>&data) {
    for(auto &e : data) {
        os << e << ' ';
    }
    return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
   // Beispielcode hier
}

Listing 24.46: Wenn Sie die Vergleichsoperation falsch definieren, funktioniert »set« nicht mehr.

Book listing lst-0757-book.cpp:

// https://godbolt.org/z/GbPsraKxa 
using std::cout; using std::ostream; using std::set;
auto vergl = [](auto e, auto f) { return e <= f; }; //                                          (ERR)  ungültig definiert!
std::set<int,decltype(vergl)> data(vergl);
data.insert({ 9,5,7,2,3,6,8 });
cout <<= data;                     // Ausgabe mit Glück: 2 3 5 6 7 8 9
auto wo = data.find(7);
if(wo != data.end()) {
    cout << "hab es: " << *wo << '\n';
} else {
    cout << "weg isses!" << '\n'; // wahrscheinlich landen Sie hier
}

Godbolt Listing lst-0757-godb.cpp, https://godbolt.org/z/GbPsraKxa:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/GbPsraKxa 
using std::cout; using std::ostream; using std::set;
auto vergl = [](auto e, auto f) { return e <= f; }; //                                          (ERR)  ungültig definiert!
std::set<int,decltype(vergl)> data(vergl);
data.insert({ 9,5,7,2,3,6,8 });
cout <<= data;                     // Ausgabe mit Glück: 2 3 5 6 7 8 9
auto wo = data.find(7);
if(wo != data.end()) {
    cout << "hab es: " << *wo << '\n';
} else {
    cout << "weg isses!" << '\n'; // wahrscheinlich landen Sie hier
}

Listing 24.47: Die Vergleichsoperation darf Elemente zusammenfassen.

Book listing lst-0758-book.cpp:

// https://godbolt.org/z/MeGnEez15 
auto vergl = [](auto e, auto f) {return e/10<f/10;}; // zusammenfassen ist okay
std::set<int,decltype(vergl)> data(vergl);
data.insert({ 14,23,56,71 });
cout <<= data;                         // Ausgabe: 14 23 56 71
auto wo = data.find(29);               // 29 findet nun auch die 23
if(wo != data.end()) {
    cout << "hab es: " << *wo << '\n'; // Ausgabe: hab es: 23
}
data.insert(79);                       // nichts passiert, denn 71 ist schon drin
cout <<= data;                         // Ausgabe: 14 23 56 71

Godbolt Listing lst-0758-godb.cpp, https://godbolt.org/z/MeGnEez15:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MeGnEez15 
auto vergl = [](auto e, auto f) {return e/10<f/10;}; // zusammenfassen ist okay
std::set<int,decltype(vergl)> data(vergl);
data.insert({ 14,23,56,71 });
cout <<= data;                         // Ausgabe: 14 23 56 71
auto wo = data.find(29);               // 29 findet nun auch die 23
if(wo != data.end()) {
    cout << "hab es: " << *wo << '\n'; // Ausgabe: hab es: 23
}
data.insert(79);                       // nichts passiert, denn 71 ist schon drin
cout <<= data;                         // Ausgabe: 14 23 56 71

Listing 24.48: Ein eigener Spaceship-Operator für die »set«-Kompatibilität

Book listing lst-0759-book.cpp:

// https://godbolt.org/z/a3cnTn3zz 
#include <iostream>
#include <set>
#include <string>
struct Dwarf {
  std::string name;
  int height;
  auto operator<=>(const Dwarf& other) const {
    return height <=> other.height;
  }
};
int main() {
  std::set<Dwarf> dwarves {
    {"Thorin", 140}, {"Balin", 136}, {"Kili", 138},
    {"Dwalin", 139}, {"Oin", 135},   {"Gloin", 137},
  };
  for(auto &d: dwarves) {
    std::cout << d.name << ' ';
  } // Ausgabe: Oin Balin Kili Gloin Dwalin Thorin
}

Godbolt Listing lst-0759-godb.cpp, https://godbolt.org/z/a3cnTn3zz:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a3cnTn3zz 
#include <iostream>
#include <set>
#include <string>
struct Dwarf {
  std::string name;
  int height;
  auto operator<=>(const Dwarf& other) const {
    return height <=> other.height;
  }
};
int main() {
  std::set<Dwarf> dwarves {
    {"Thorin", 140}, {"Balin", 136}, {"Kili", 138},
    {"Dwalin", 139}, {"Oin", 135},   {"Gloin", 137},
  };
  for(auto &d: dwarves) {
    std::cout << d.name << ' ';
  } // Ausgabe: Oin Balin Kili Gloin Dwalin Thorin
}

Listing 24.49: Es gibt verschiedene Möglichkeiten, einen Comparator anzugeben.

Book listing lst-0761-book.cpp:

// https://godbolt.org/z/1Eoh9aoas 
#include <set>
#include <functional> // function
using std::set; using std::function; using std::initializer_list;
bool fcompZehner(int a, int b) { return a%10 < b%10; }
struct Fuenfer {
    bool operator()(int a, int b) const { return a%5 < b% 5; }
};

int main() {
    // Funktor
    set<int, Fuenfer> ff1;
    ff1.insert(5);
    set ff2({5}, Fuenfer{}); 
    set ff3(initializer_list<int>({}), Fuenfer{});
    // Lambda
    set<int,function<bool(int,int)>> ll1([](auto a,auto b){return a%3<b%3;});
    ll1.insert(3);
    auto lcomp = [](int a, int b) { return a%3 < b%3; };
    set<int, decltype(lcomp)> ll2(lcomp);
    ll2.insert(3);
    set ll3({3}, lcomp); 
    // Funktionszeiger
    set<int, bool(*)(int,int)> zz1(&fcompZehner);        // C-Stil
    zz1.insert(10);
    set<int, function<bool(int,int)>> zz2(&fcompZehner); // C++-Stil
    zz2.insert(10);
    set<int, decltype(&fcompZehner)> zz3(&fcompZehner);  // C++-Stil
    zz3.insert(10);
}

Godbolt Listing lst-0761-godb.cpp, https://godbolt.org/z/1Eoh9aoas:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1Eoh9aoas 
#include <set>
#include <functional> // function
using std::set; using std::function; using std::initializer_list;
bool fcompZehner(int a, int b) { return a%10 < b%10; }
struct Fuenfer {
    bool operator()(int a, int b) const { return a%5 < b% 5; }
};

int main() {
    // Funktor
    set<int, Fuenfer> ff1;
    ff1.insert(5);
    set ff2({5}, Fuenfer{}); 
    set ff3(initializer_list<int>({}), Fuenfer{});
    // Lambda
    set<int,function<bool(int,int)>> ll1([](auto a,auto b){return a%3<b%3;});
    ll1.insert(3);
    auto lcomp = [](int a, int b) { return a%3 < b%3; };
    set<int, decltype(lcomp)> ll2(lcomp);
    ll2.insert(3);
    set ll3({3}, lcomp); 
    // Funktionszeiger
    set<int, bool(*)(int,int)> zz1(&fcompZehner);        // C-Stil
    zz1.insert(10);
    set<int, function<bool(int,int)>> zz2(&fcompZehner); // C++-Stil
    zz2.insert(10);
    set<int, decltype(&fcompZehner)> zz3(&fcompZehner);  // C++-Stil
    zz3.insert(10);
}

Listing 24.50: Es gibt wieder mehrere Möglichkeiten, beim Konstruieren Elemente anzugeben.

Book listing lst-0762-book.cpp:

// https://godbolt.org/z/56rb9qfed 
// ohne Argumente
set<int> leer{};
cout <<= leer;           // Ausgabe:
// Initialisierungsliste
set liste{ 1,1,2,2,3,3,4,4,5,5 };  // set übernimmt keine Doppelten
cout <<= liste;          // Ausgabe: 1 2 3 4 5
// Kopie
set copy(liste);
cout <<= copy;           // Ausgabe: 1 2 3 4 5
// Iteratorpaar
set from_to( std::next(liste.begin()), std::prev(liste.end()));
cout <<= from_to;        // Ausgabe: 2 3 4
// Range
set gerade(from_range, liste | vs::filter([](int i){ return i%2; }));
cout <<= from_to;        // Ausgabe: 2 4

Godbolt Listing lst-0762-godb.cpp, https://godbolt.org/z/56rb9qfed:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/56rb9qfed 
// ohne Argumente
set<int> leer{};
cout <<= leer;           // Ausgabe:
// Initialisierungsliste
set liste{ 1,1,2,2,3,3,4,4,5,5 };  // set übernimmt keine Doppelten
cout <<= liste;          // Ausgabe: 1 2 3 4 5
// Kopie
set copy(liste);
cout <<= copy;           // Ausgabe: 1 2 3 4 5
// Iteratorpaar
set from_to( std::next(liste.begin()), std::prev(liste.end()));
cout <<= from_to;        // Ausgabe: 2 3 4
// Range
set gerade(from_range, liste | vs::filter([](int i){ return i%2; }));
cout <<= from_to;        // Ausgabe: 2 4

GodboltId:1dTPEd3nP

Book listing lst-0763-book.cpp:

// https://godbolt.org/z/1dTPEd3nP 
set quelle{1,2,3,4,5};
cout <<= quelle;           // Ausgabe: 1 2 3 4 5
set ziel( std::move(quelle) ); // verschieben statt kopieren
cout <<= quelle;           // Ausgabe:
cout <<= ziel;             // Ausgabe: 1 2 3 4 5

Godbolt Listing lst-0763-godb.cpp, https://godbolt.org/z/1dTPEd3nP:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1dTPEd3nP 
set quelle{1,2,3,4,5};
cout <<= quelle;           // Ausgabe: 1 2 3 4 5
set ziel( std::move(quelle) ); // verschieben statt kopieren
cout <<= quelle;           // Ausgabe:
cout <<= ziel;             // Ausgabe: 1 2 3 4 5

GodboltId:8eGvWY45o

Book listing lst-0764-book.cpp:

// https://godbolt.org/z/8eGvWY45o 
set quelle{1,2,3,4,5};
set<int> ziel{};
set<int> ziel2{};
cout <<= quelle;           // Ausgabe: 1 2 3 4 5
cout <<= ziel;             // Ausgabe:
cout <<= ziel2;            // Ausgabe:
ziel = quelle;             // nachträglich kopieren
cout <<= quelle;           // Ausgabe: 1 2 3 4 5
cout <<= ziel;             // Ausgabe: 1 2 3 4 5
ziel2 = std::move(quelle); // verschieben
cout <<= quelle;           // Ausgabe:
cout <<= ziel2;            // Ausgabe: 1 2 3 4 5

Godbolt Listing lst-0764-godb.cpp, https://godbolt.org/z/8eGvWY45o:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8eGvWY45o 
set quelle{1,2,3,4,5};
set<int> ziel{};
set<int> ziel2{};
cout <<= quelle;           // Ausgabe: 1 2 3 4 5
cout <<= ziel;             // Ausgabe:
cout <<= ziel2;            // Ausgabe:
ziel = quelle;             // nachträglich kopieren
cout <<= quelle;           // Ausgabe: 1 2 3 4 5
cout <<= ziel;             // Ausgabe: 1 2 3 4 5
ziel2 = std::move(quelle); // verschieben
cout <<= quelle;           // Ausgabe:
cout <<= ziel2;            // Ausgabe: 1 2 3 4 5

Listing 24.51: Statt »assign« können Sie das Copy-and-swap-Idiom verwenden.

Book listing lst-0765-book.cpp:

// https://godbolt.org/z/1vGPo9a99 
#include <vector>
// …
set data{1,2,3,4,5};
std::vector quelle{10, 20, 30, 40, 50};

// Es gibt kein set::assign:
data.assign(quelle.begin(), quelle.end());   //                                          (ERR)  kein set::assign
// Simulieren Sie es also mittels eines temporären set:
set temp(quelle.begin(), quelle.end());      // aus Quelle kopieren …
data.swap(temp);                             // … Inhalte effizient vertauschen
cout <<= data; // Ausgabe: 10 20 30 40 50
// … oder per vorherigem clear und darauffolgendem insert:
data.clear();                                // leeren …
data.insert(quelle.begin(), quelle.end());   // … und einfügen
cout <<= data; // Ausgabe: 10 20 30 40 50

Godbolt Listing lst-0765-godb.cpp, https://godbolt.org/z/1vGPo9a99:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1vGPo9a99 
#include <vector>
// …
set data{1,2,3,4,5};
std::vector quelle{10, 20, 30, 40, 50};

// Es gibt kein set::assign:
data.assign(quelle.begin(), quelle.end());   //                                          (ERR)  kein set::assign
// Simulieren Sie es also mittels eines temporären set:
set temp(quelle.begin(), quelle.end());      // aus Quelle kopieren …
data.swap(temp);                             // … Inhalte effizient vertauschen
cout <<= data; // Ausgabe: 10 20 30 40 50
// … oder per vorherigem clear und darauffolgendem insert:
data.clear();                                // leeren …
data.insert(quelle.begin(), quelle.end());   // … und einfügen
cout <<= data; // Ausgabe: 10 20 30 40 50

Listing 24.52: Zum Einfügen eines einzelnen Elements nehmen Sie »insert« oder »emplace«.

Book listing lst-0766-book.cpp:

// https://godbolt.org/z/PjEKKben4 
// …
template<typename IT> ostream& operator<<(ostream& os,const pair<IT,bool> wo)
  { return os << (wo.second ? "ja" : "nein"); }
struct Punkt {
    double x_, y_;
    Punkt(double x, double y) : x_{x}, y_{y} {}
    auto operator<=>(const Punkt&) const = default;
    friend ostream& operator<<(ostream &os, const Punkt &a) {
        return os << "(" << a.x_ << ',' << a.y_<< ")";
    }
};
int main() {
    set data{ 10, 20, 30, 40, 50, 60, 70 };
    auto wo = data.insert(35);         // fügt zwischen 30 und 40 ein
    cout << "neu? " << wo << '\n';     // Ausgabe: neu? ja
    wo = data.insert(40);              // gibt es schon, fügt also nicht ein
    cout << "neu? " << wo << '\n';     // Ausgabe: neu? nein
    set<Punkt> punkte{};
    punkte.insert( Punkt{3.50,7.25} ); // temporärer Wert
    punkte.emplace(1.25, 2.00);        // Konstruktorargumente
    cout <<= punkte;                   // Ausgabe: (1.25,2) (3.5,7.25)
}

Godbolt Listing lst-0766-godb.cpp, https://godbolt.org/z/PjEKKben4:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/PjEKKben4 
// …
template<typename IT> ostream& operator<<(ostream& os,const pair<IT,bool> wo)
  { return os << (wo.second ? "ja" : "nein"); }
struct Punkt {
    double x_, y_;
    Punkt(double x, double y) : x_{x}, y_{y} {}
    auto operator<=>(const Punkt&) const = default;
    friend ostream& operator<<(ostream &os, const Punkt &a) {
        return os << "(" << a.x_ << ',' << a.y_<< ")";
    }
};
int main() {
    set data{ 10, 20, 30, 40, 50, 60, 70 };
    auto wo = data.insert(35);         // fügt zwischen 30 und 40 ein
    cout << "neu? " << wo << '\n';     // Ausgabe: neu? ja
    wo = data.insert(40);              // gibt es schon, fügt also nicht ein
    cout << "neu? " << wo << '\n';     // Ausgabe: neu? nein
    set<Punkt> punkte{};
    punkte.insert( Punkt{3.50,7.25} ); // temporärer Wert
    punkte.emplace(1.25, 2.00);        // Konstruktorargumente
    cout <<= punkte;                   // Ausgabe: (1.25,2) (3.5,7.25)
}

Listing 24.53: Die Rückgabe können Sie beim Einfügen sortierter Bereiche wiederverwenden.

Book listing lst-0767-book.cpp:

// https://godbolt.org/z/qzaj79bor 
set data{ 10, 20, 30, 40, 50, 60, 70 };
set<int> ziel;
auto hinweis = ziel.begin();
for(auto &e : data) {
    hinweis =                    // Einfügeposition in nächster Runde nutzen
        ziel.insert(hinweis, e); // Hinweis hilft, weil data sortiert ist
}

Godbolt Listing lst-0767-godb.cpp, https://godbolt.org/z/qzaj79bor:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qzaj79bor 
set data{ 10, 20, 30, 40, 50, 60, 70 };
set<int> ziel;
auto hinweis = ziel.begin();
for(auto &e : data) {
    hinweis =                    // Einfügeposition in nächster Runde nutzen
        ziel.insert(hinweis, e); // Hinweis hilft, weil data sortiert ist
}

Listing 24.54: Nehmen Sie das gleiche insert bei sequenziellen und assoziativen Containern.

Book listing lst-0768-book.cpp:

// https://godbolt.org/z/nW3Gxe5Ye 
#include <set>
#include <vector>
#include <iostream>
using std::cout; using std::ostream; using std::set; using std::vector;

template<typename Container>
void insFive(Container& cont, int a, int b, int c, int d, int e) {
    auto it = cont.end();
    for(int x : { a, b, c, d, e }) {
        it = cont.insert(it, x); // geht mit vector, set etc.
    }
}
int main() {
    vector<int> dataVec{ };
    insFive(dataVec, 9, 2, 2, 0, 4 );
    for(auto e : dataVec) cout <<e<<' ';
    cout << '\n'; // Ausgabe: 4 0 2 2 9
    set<int> dataSet{ };
    insFive(dataSet, 9, 4, 2, 2, 0);
    for(auto e : dataSet) cout <<e<<' ';
    cout << '\n'; // Ausgabe: 0 2 4 9
}

Godbolt Listing lst-0768-godb.cpp, https://godbolt.org/z/nW3Gxe5Ye:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/nW3Gxe5Ye 
#include <set>
#include <vector>
#include <iostream>
using std::cout; using std::ostream; using std::set; using std::vector;

template<typename Container>
void insFive(Container& cont, int a, int b, int c, int d, int e) {
    auto it = cont.end();
    for(int x : { a, b, c, d, e }) {
        it = cont.insert(it, x); // geht mit vector, set etc.
    }
}
int main() {
    vector<int> dataVec{ };
    insFive(dataVec, 9, 2, 2, 0, 4 );
    for(auto e : dataVec) cout <<e<<' ';
    cout << '\n'; // Ausgabe: 4 0 2 2 9
    set<int> dataSet{ };
    insFive(dataSet, 9, 4, 2, 2, 0);
    for(auto e : dataSet) cout <<e<<' ';
    cout << '\n'; // Ausgabe: 0 2 4 9
}

Listing 24.55: Sie können auch mehrere Elemente einfügen.

Book listing lst-0769-book.cpp:

// https://godbolt.org/z/rTvovhr5M 
#include <vector>
set data{ 10, 20, 30, };
data.insert( { 40, 50, 60, 70 }); // Initialisierungsliste
std::vector neu{ 5, 25, 35, 15, 25, 75, 95 };
data.insert( neu.cbegin()+1, neu.cend()-1 ); // Bereich
cout <<= data; // Ausgabe: 10 15 20 25 30 35 40 50 60 70 75

Godbolt Listing lst-0769-godb.cpp, https://godbolt.org/z/rTvovhr5M:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rTvovhr5M 
#include <vector>
set data{ 10, 20, 30, };
data.insert( { 40, 50, 60, 70 }); // Initialisierungsliste
std::vector neu{ 5, 25, 35, 15, 25, 75, 95 };
data.insert( neu.cbegin()+1, neu.cend()-1 ); // Bereich
cout <<= data; // Ausgabe: 10 15 20 25 30 35 40 50 60 70 75

Listing 24.56: Dies sind die »set«-Suchfunktionen.

Book listing lst-0770-book.cpp:

// https://godbolt.org/z/xnv9Wbxbz 
#include <set>
#include <iostream>
using std::cout; using std::ostream; using std::set;
void suchmal(const set<int>&data, int was, ostream&os) {
    os << was << "? ";
    // enthält
    auto drin = data.contains(was);  // C++20
    os << "drin:" << (drin ? "ja." : "nein."); // enthält prüfen
    auto wo = data.find(was);
    if(wo != data.end()) {
        os << " gefunden:" << *wo << " ";
    } else {
        os << " nicht gefunden. ";
    }
    auto lo = data.lower_bound(was);
    if(lo != data.end()) {
        os << "lo:" << *lo;
    } else {
        os << "lo:-";
    }
    auto up = data.upper_bound(was);
    if(up != data.end()) {
        os << " up:" << *up;
    } else {
        os << " up:-";
    }
    // [lo,up] ist nun das Gleiche, was equal_range geliefert hätte
    os << " Bereich:{";
    for( ; lo != up; ++ lo) {
      os << *lo << ' ';
    }
    os << "}";
    // zählen
    os << " C:" << data.count(was) // Treffer zählen
       << "\n";
}
int main() {
    set data{ 10, 20, 30, 40, 50, 60 };
    suchmal(data, 20, cout); // 20? drin:ja. gefunden:20 lo:20 up:30 Bereich:{20 } C:1
    suchmal(data, 25, cout); // 25? drin:nein. lo:30 up:30 Bereich:{} C:0
    suchmal(data, 10, cout); // 10? drin:ja. gefunden:10 lo:10 up:20 Bereich:{10 } C:1
    suchmal(data, 60, cout); // 60? drin:ja. gefunden:60 lo:60 up:- Bereich:{60 } C:1
    suchmal(data, 5, cout);  // 5? drin:nein. lo:10 up:10 Bereich:{} C:0
    suchmal(data, 99, cout); // 99? drin:nein. lo:- up:- Bereich:{} C:0
}

Godbolt Listing lst-0770-godb.cpp, https://godbolt.org/z/xnv9Wbxbz:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xnv9Wbxbz 
#include <set>
#include <iostream>
using std::cout; using std::ostream; using std::set;
void suchmal(const set<int>&data, int was, ostream&os) {
    os << was << "? ";
    // enthält
    auto drin = data.contains(was);  // C++20
    os << "drin:" << (drin ? "ja." : "nein."); // enthält prüfen
    auto wo = data.find(was);
    if(wo != data.end()) {
        os << " gefunden:" << *wo << " ";
    } else {
        os << " nicht gefunden. ";
    }
    auto lo = data.lower_bound(was);
    if(lo != data.end()) {
        os << "lo:" << *lo;
    } else {
        os << "lo:-";
    }
    auto up = data.upper_bound(was);
    if(up != data.end()) {
        os << " up:" << *up;
    } else {
        os << " up:-";
    }
    // [lo,up] ist nun das Gleiche, was equal_range geliefert hätte
    os << " Bereich:{";
    for( ; lo != up; ++ lo) {
      os << *lo << ' ';
    }
    os << "}";
    // zählen
    os << " C:" << data.count(was) // Treffer zählen
       << "\n";
}
int main() {
    set data{ 10, 20, 30, 40, 50, 60 };
    suchmal(data, 20, cout); // 20? drin:ja. gefunden:20 lo:20 up:30 Bereich:{20 } C:1
    suchmal(data, 25, cout); // 25? drin:nein. lo:30 up:30 Bereich:{} C:0
    suchmal(data, 10, cout); // 10? drin:ja. gefunden:10 lo:10 up:20 Bereich:{10 } C:1
    suchmal(data, 60, cout); // 60? drin:ja. gefunden:60 lo:60 up:- Bereich:{60 } C:1
    suchmal(data, 5, cout);  // 5? drin:nein. lo:10 up:10 Bereich:{} C:0
    suchmal(data, 99, cout); // 99? drin:nein. lo:- up:- Bereich:{} C:0
}

Listing 24.57: Sie können mit nicht identischen Schlüsseln suchen, wenn diese äquivalent sind.

Book listing lst-0771-book.cpp:

// https://godbolt.org/z/jGfeT94as 
#include <string>
#include <set>
#include <iostream>
#include <tuple> // tuple, tie
using std::string; using std::set; using std::cout; using std::tie;
struct Hobbit {
  string vorname;
  string nachname;
  Hobbit(const string v, const string n) : vorname{v}, nachname{n} {}
};
struct CompNachname {
  bool operator()(const Hobbit& x, const Hobbit& y) const { // normales <
    return tie(x.nachname, x.vorname) < tie(y.nachname, y.vorname);
  }
  using is_transparent = std::true_type; // für find erlaubt
  bool operator()(const Hobbit& x, const string& y) const { // für find etc.
    return x.nachname < y;
  }
  bool operator()(const string& x, const Hobbit& y) const { // für find etc.
    return x < y.nachname;
  }
};
int main() {
    using namespace std::literals; // erlaube "…"s
    set<Hobbit,CompNachname> hobbits;
    hobbits.emplace( "Frodo", "Baggins" );
    hobbits.emplace( "Sam", "Gamgee" );
    auto f1 = hobbits.find( Hobbit{"Frodo", "Baggins"} ); // ganzer Schlüssel
    if(f1 != hobbits.end()) {
        cout << "gefunden: " << f1->vorname << '\n'; // Frodo
    }
    auto f2 = hobbits.find( "Gamgee"s );             // äquivalenter Schlüssel
    if(f2 != hobbits.end()) {
        cout << "gefunden: " << f2->vorname << '\n'; // Sam
    }
}

Godbolt Listing lst-0771-godb.cpp, https://godbolt.org/z/jGfeT94as:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jGfeT94as 
#include <string>
#include <set>
#include <iostream>
#include <tuple> // tuple, tie
using std::string; using std::set; using std::cout; using std::tie;
struct Hobbit {
  string vorname;
  string nachname;
  Hobbit(const string v, const string n) : vorname{v}, nachname{n} {}
};
struct CompNachname {
  bool operator()(const Hobbit& x, const Hobbit& y) const { // normales <
    return tie(x.nachname, x.vorname) < tie(y.nachname, y.vorname);
  }
  using is_transparent = std::true_type; // für find erlaubt
  bool operator()(const Hobbit& x, const string& y) const { // für find etc.
    return x.nachname < y;
  }
  bool operator()(const string& x, const Hobbit& y) const { // für find etc.
    return x < y.nachname;
  }
};
int main() {
    using namespace std::literals; // erlaube "…"s
    set<Hobbit,CompNachname> hobbits;
    hobbits.emplace( "Frodo", "Baggins" );
    hobbits.emplace( "Sam", "Gamgee" );
    auto f1 = hobbits.find( Hobbit{"Frodo", "Baggins"} ); // ganzer Schlüssel
    if(f1 != hobbits.end()) {
        cout << "gefunden: " << f1->vorname << '\n'; // Frodo
    }
    auto f2 = hobbits.find( "Gamgee"s );             // äquivalenter Schlüssel
    if(f2 != hobbits.end()) {
        cout << "gefunden: " << f2->vorname << '\n'; // Sam
    }
}

Listing 24.58: »erase« löscht ein oder mehrere Elemente.

Book listing lst-0773-book.cpp:

// https://godbolt.org/z/xW9bTqfG4 
set data{ 10, 20, 30, 40, 50, 60, 70 };
auto lo = data.lower_bound(35);
auto up = data.upper_bound(55);
data.erase(lo, up);      // löscht alle Zahlen zwischen 35 und 55
cout <<= data;           // Ausgabe: 10 20 30 60 70
lo = data.lower_bound(20);
up = data.upper_bound(60);
data.erase(lo, up);      // löscht inklusive 60, weil up auf 70 verweist
cout <<= data;           // Ausgabe: 10 70
auto n = data.erase(69); // löscht nichts
cout << "Anzahl entfernter Elemente: "<< n << '\n'; // Ausgabe: Anzahl … 0
n = data.erase(70);      // löscht ein Element
cout << "Anzahl entfernter Elemente: "<< n << '\n';  // Ausgabe: Anzahl … 1
cout <<= data;           // Ausgabe: 10

Godbolt Listing lst-0773-godb.cpp, https://godbolt.org/z/xW9bTqfG4:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xW9bTqfG4 
set data{ 10, 20, 30, 40, 50, 60, 70 };
auto lo = data.lower_bound(35);
auto up = data.upper_bound(55);
data.erase(lo, up);      // löscht alle Zahlen zwischen 35 und 55
cout <<= data;           // Ausgabe: 10 20 30 60 70
lo = data.lower_bound(20);
up = data.upper_bound(60);
data.erase(lo, up);      // löscht inklusive 60, weil up auf 70 verweist
cout <<= data;           // Ausgabe: 10 70
auto n = data.erase(69); // löscht nichts
cout << "Anzahl entfernter Elemente: "<< n << '\n'; // Ausgabe: Anzahl … 0
n = data.erase(70);      // löscht ein Element
cout << "Anzahl entfernter Elemente: "<< n << '\n';  // Ausgabe: Anzahl … 1
cout <<= data;           // Ausgabe: 10

Listing 24.59: Mit »[]« erzeugen Sie als Seiteneffekt eventuell einen Eintrag.

Book listing lst-0774-book.cpp:

// https://godbolt.org/z/zWa58dYYq 
#include <map>
#include <iostream>
using std::map; using std::cout;
int main() {
    map<int,char> alpha;
    cout << alpha.size() << '\n';       // 0 natürlich
    if( alpha[5] == '3' ) { /* ... */ }
    cout << alpha.size() << '\n';       // nun 1
    char x = alpha[99];                 // klappt
    cout << alpha.size() << '\n';       // und nun 2
}

Godbolt Listing lst-0774-godb.cpp, https://godbolt.org/z/zWa58dYYq:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zWa58dYYq 
#include <map>
#include <iostream>
using std::map; using std::cout;
int main() {
    map<int,char> alpha;
    cout << alpha.size() << '\n';       // 0 natürlich
    if( alpha[5] == '3' ) { /* ... */ }
    cout << alpha.size() << '\n';       // nun 1
    char x = alpha[99];                 // klappt
    cout << alpha.size() << '\n';       // und nun 2
}

Listing 24.60: Dies ist die Schablone für die Beispiellistings dieses Abschnitts zur »map«.

Book listing lst-0775-book.cpp:

// https://godbolt.org/z/Eovd71TbT 
#include <map>        // die Hauptsache
#include <iostream>   // zur Ausgabe
#include <string>     // gerne mal Schlüssel oder Ziel
using std::map; using std::cout; using std::string;
template<typename Key, typename Trg, typename Comp>
std::ostream& operator<<=(std::ostream&os, const map<Key,Trg,Comp>&data) {
    for(auto &e : data) os << e.first << ":" << e.second << ' ';
    return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
   // Beispielcode hier
}

Godbolt Listing lst-0775-godb.cpp, https://godbolt.org/z/Eovd71TbT:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Eovd71TbT 
#include <map>        // die Hauptsache
#include <iostream>   // zur Ausgabe
#include <string>     // gerne mal Schlüssel oder Ziel
using std::map; using std::cout; using std::string;
template<typename Key, typename Trg, typename Comp>
std::ostream& operator<<=(std::ostream&os, const map<Key,Trg,Comp>&data) {
    for(auto &e : data) os << e.first << ":" << e.second << ' ';
    return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
   // Beispielcode hier
}

Listing 24.61: Auch bei einer »map« können Sie eine eigene Vergleichsfunktion mitgeben.

Book listing lst-0776-book.cpp:

// https://godbolt.org/z/nfs15n1Mn 
#include <cstdio> // toupper, tolower
// …
auto comp = [](char a, char b) { return toupper(a) < toupper(b); };
map<char,int,decltype(comp)> lets(comp); // als Templateparameter und Argument
lets['a'] = 1;
lets['B'] = 2;
lets['c'] = 3;
lets['A'] = 4; // überschreibt Position 'a'
cout <<= lets; // Ausgabe: a:4 B:2 c:3
struct Comp {  // Funktor
    bool operator()(char a, char b) const { return toupper(a) < toupper(b); }
};
map<char,int,Comp> lets2; // hier reicht der Templateparameter

Godbolt Listing lst-0776-godb.cpp, https://godbolt.org/z/nfs15n1Mn:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/nfs15n1Mn 
#include <cstdio> // toupper, tolower
// …
auto comp = [](char a, char b) { return toupper(a) < toupper(b); };
map<char,int,decltype(comp)> lets(comp); // als Templateparameter und Argument
lets['a'] = 1;
lets['B'] = 2;
lets['c'] = 3;
lets['A'] = 4; // überschreibt Position 'a'
cout <<= lets; // Ausgabe: a:4 B:2 c:3
struct Comp {  // Funktor
    bool operator()(char a, char b) const { return toupper(a) < toupper(b); }
};
map<char,int,Comp> lets2; // hier reicht der Templateparameter

Listing 24.62: Die Initialisierungsliste muss »pair«-Elemente enthalten.

Book listing lst-0778-book.cpp:

// https://godbolt.org/z/79xx8ddoY 
using std::pair; using std::make_pair;
namespace literal_p { // benutzerdefinierte Literale besser in Namespace packen
constexpr pair<char,char> operator "" _p(const char* s, size_t len) {
    return len>=2 ?make_pair(s[0], s[1]) : make_pair( '-', '-' );
} }
struct Q {
    char a_; int n_;
    Q(char a, int n) : a_{a}, n_{n} {}
    operator pair<const char,int>() { return make_pair(a_, n_); }
};
// …
// explizite Paare:
map<int,int> nums { pair<int,int>(3,4), make_pair(7,8), make_pair(11,23) };
map nums2 { pair<int,int>(6,1), make_pair(5,2) };
// implizite Paare aus Initialisierungslisten:
map<int,char> numch{{1,'a'},{2,'b'},{3,'c'}};
map<int,int> nums3 { {7,2}, {9,4} };
using namespace literal_p;
map<char,char> pmap { "ab"_p, "cd"_p, "ef"_p }; // Umweg über eigenes Literal
cout <<= pmap;                                  // Ausgabe: a:b c:d e:f
map<char,int> qmap{Q('a',1),Q('b',2),Q('c',3)}; // implizite Umwandlungen
cout <<= qmap;                                  // Ausgabe: a:1 b:2 c:3

Godbolt Listing lst-0778-godb.cpp, https://godbolt.org/z/79xx8ddoY:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/79xx8ddoY 
using std::pair; using std::make_pair;
namespace literal_p { // benutzerdefinierte Literale besser in Namespace packen
constexpr pair<char,char> operator "" _p(const char* s, size_t len) {
    return len>=2 ?make_pair(s[0], s[1]) : make_pair( '-', '-' );
} }
struct Q {
    char a_; int n_;
    Q(char a, int n) : a_{a}, n_{n} {}
    operator pair<const char,int>() { return make_pair(a_, n_); }
};
// …
// explizite Paare:
map<int,int> nums { pair<int,int>(3,4), make_pair(7,8), make_pair(11,23) };
map nums2 { pair<int,int>(6,1), make_pair(5,2) };
// implizite Paare aus Initialisierungslisten:
map<int,char> numch{{1,'a'},{2,'b'},{3,'c'}};
map<int,int> nums3 { {7,2}, {9,4} };
using namespace literal_p;
map<char,char> pmap { "ab"_p, "cd"_p, "ef"_p }; // Umweg über eigenes Literal
cout <<= pmap;                                  // Ausgabe: a:b c:d e:f
map<char,int> qmap{Q('a',1),Q('b',2),Q('c',3)}; // implizite Umwandlungen
cout <<= qmap;                                  // Ausgabe: a:1 b:2 c:3

Listing 24.63: Ein einzelnes neues Element geben Sie als Paar an.

Book listing lst-0779-book.cpp:

// https://godbolt.org/z/bzvrPefvY 
map<int,string> plz2ort;
plz2ort.insert(std::make_pair(53227, "Bonn"));
plz2ort.emplace(50667, "Koeln");
cout <<= plz2ort;                    // Ausgabe: 50667:Koeln 53227:Bonn
map<string,int> ort2plz;
ort2plz.emplace("Koeln", 50667);
ort2plz.emplace("Koeln", 51063);     // überschreibt nicht
cout <<= ort2plz;                    // Ausgabe: Koeln:50667

Godbolt Listing lst-0779-godb.cpp, https://godbolt.org/z/bzvrPefvY:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bzvrPefvY 
map<int,string> plz2ort;
plz2ort.insert(std::make_pair(53227, "Bonn"));
plz2ort.emplace(50667, "Koeln");
cout <<= plz2ort;                    // Ausgabe: 50667:Koeln 53227:Bonn
map<string,int> ort2plz;
ort2plz.emplace("Koeln", 50667);
ort2plz.emplace("Koeln", 51063);     // überschreibt nicht
cout <<= ort2plz;                    // Ausgabe: Koeln:50667

Listing 24.64: Mit »operator[]« automatisch erzeugen und gleich überschreiben

Book listing lst-0780-book.cpp:

// https://godbolt.org/z/7h3vsWvYG 
map<string,int> zwerge;
zwerge.emplace("Fili",  2859);
cout << zwerge["Fili"] << '\n'; // Ausgabe: 2859
cout << zwerge["Dori"] << '\n'; // neu erzeugt. Ausgabe: 0
zwerge["Kili"] = 2846;          // neu erzeugt und gleich überschrieben
cout << zwerge["Kili"] << '\n'; // Ausgabe: 2846
cout <<= zwerge;                // Ausgabe: Dori:0 Fili:2859 Kili:2846

Godbolt Listing lst-0780-godb.cpp, https://godbolt.org/z/7h3vsWvYG:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7h3vsWvYG 
map<string,int> zwerge;
zwerge.emplace("Fili",  2859);
cout << zwerge["Fili"] << '\n'; // Ausgabe: 2859
cout << zwerge["Dori"] << '\n'; // neu erzeugt. Ausgabe: 0
zwerge["Kili"] = 2846;          // neu erzeugt und gleich überschrieben
cout << zwerge["Kili"] << '\n'; // Ausgabe: 2846
cout <<= zwerge;                // Ausgabe: Dori:0 Fili:2859 Kili:2846

Listing 24.65: Sie können den Wert eines Ziels ändern.

Book listing lst-0781-book.cpp:

// https://godbolt.org/z/7E6cr8GE9 
map<string,string> data { {"Hans","Albers"}, {"Heinz","Ruehmann" }, };
cout <<= data;                         // Hans:Albers Heinz:Ruehmann
data.rbegin()->second = "Erhardt";     // Ziel überschreiben
cout <<= data;                         // Hans:Albers Heinz:Erhardt

Godbolt Listing lst-0781-godb.cpp, https://godbolt.org/z/7E6cr8GE9:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7E6cr8GE9 
map<string,string> data { {"Hans","Albers"}, {"Heinz","Ruehmann" }, };
cout <<= data;                         // Hans:Albers Heinz:Ruehmann
data.rbegin()->second = "Erhardt";     // Ziel überschreiben
cout <<= data;                         // Hans:Albers Heinz:Erhardt

Listing 24.66: Iteratoren von »map« sind vom Typ »pair«.

Book listing lst-0782-book.cpp:

// https://godbolt.org/z/16T5dob75 
map<char,int> data { { 'a',1}, {'b',2}, {'c',3} };
for(auto it=data.rbegin(); it!=data.rend(); ++it) {  // rückwärts
    cout << it->first << ':' << it->second << ' ';   // mit -> dereferenzieren
}
cout << '\n'; // Ausgabe: c:3 b:2 a:1
for(auto &e : data) {                          // vorwärts, nimmt begin() und end()
    cout << e.first << ':' << e.second << ' '; // Paar, Elementzugriff mit .
}
cout << '\n'; // Ausgabe: a:1 b:2 c:3

Godbolt Listing lst-0782-godb.cpp, https://godbolt.org/z/16T5dob75:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/16T5dob75 
map<char,int> data { { 'a',1}, {'b',2}, {'c',3} };
for(auto it=data.rbegin(); it!=data.rend(); ++it) {  // rückwärts
    cout << it->first << ':' << it->second << ' ';   // mit -> dereferenzieren
}
cout << '\n'; // Ausgabe: c:3 b:2 a:1
for(auto &e : data) {                          // vorwärts, nimmt begin() und end()
    cout << e.first << ':' << e.second << ' '; // Paar, Elementzugriff mit .
}
cout << '\n'; // Ausgabe: a:1 b:2 c:3

Listing 24.67: Sie können »operator[]« nicht auf einer »const map« verwenden.

Book listing lst-0783-book.cpp:

// https://godbolt.org/z/54zqqhzh6 
string such7(const map<int,string> &data) {
    return data[7];            //                                                  (ERR)  non-const-Methode auf const-Parameter
}
string such5(const map<int,string> &data) {
    auto it = data.find(5);    // nicht automatisch einfügend
    return it==data.end() ? string{} : it->second;
}
// …
map<int,string> zwerge{ {1,"eins"}, {3,"drei"}, {5,"fuenf"}, {7,"sieben"} };
cout << such7(zwerge) << '\n';
cout << such5(zwerge) << '\n';  // Ausgabe: fuenf

Godbolt Listing lst-0783-godb.cpp, https://godbolt.org/z/54zqqhzh6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/54zqqhzh6 
string such7(const map<int,string> &data) {
    return data[7];            //                                                  (ERR)  non-const-Methode auf const-Parameter
}
string such5(const map<int,string> &data) {
    auto it = data.find(5);    // nicht automatisch einfügend
    return it==data.end() ? string{} : it->second;
}
// …
map<int,string> zwerge{ {1,"eins"}, {3,"drei"}, {5,"fuenf"}, {7,"sieben"} };
cout << such7(zwerge) << '\n';
cout << such5(zwerge) << '\n';  // Ausgabe: fuenf

Listing 24.68: Dies ist die Schablone für die Beispiellistings dieses Abschnitts zu »multiset«.

Book listing lst-0784-book.cpp:

// https://godbolt.org/z/PYbexWex3 
#include <set>     // multiset
#include <iostream>
using std::multiset; using std::cout;
template<typename Elem, typename Comp>
std::ostream& operator<<=(std::ostream&os, const multiset<Elem,Comp>&data) {
    for(auto &e : data) {
        os << e << ' ';
    }
    return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
   // Beispielcode hier
}

Godbolt Listing lst-0784-godb.cpp, https://godbolt.org/z/PYbexWex3:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/PYbexWex3 
#include <set>     // multiset
#include <iostream>
using std::multiset; using std::cout;
template<typename Elem, typename Comp>
std::ostream& operator<<=(std::ostream&os, const multiset<Elem,Comp>&data) {
    for(auto &e : data) {
        os << e << ' ';
    }
    return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
   // Beispielcode hier
}

Listing 24.69: Einträge werden sortiert, doppelte bleiben erhalten.

Book listing lst-0785-book.cpp:

// https://godbolt.org/z/Mej9GjT1j 
#include <vector>
// …
multiset msinit{1,2,2,3,1};                   // sortiert bei Initialisierung
cout <<= msinit; // Ausgabe: 1 1 2 2 3
std::vector in{ 7,7,7,7,7,7,7 };
std::set srange( in.begin(), in.end() );      // set entfernt doppelte
cout << srange.size() << ": " << *srange.begin() << '\n'; // Ausgabe: 1: 7
multiset msrange( in.begin(), in.end() );      // multiset erhält doppelte
cout <<= msrange; // Ausgabe: 7 7 7 7 7 7 7

Godbolt Listing lst-0785-godb.cpp, https://godbolt.org/z/Mej9GjT1j:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Mej9GjT1j 
#include <vector>
// …
multiset msinit{1,2,2,3,1};                   // sortiert bei Initialisierung
cout <<= msinit; // Ausgabe: 1 1 2 2 3
std::vector in{ 7,7,7,7,7,7,7 };
std::set srange( in.begin(), in.end() );      // set entfernt doppelte
cout << srange.size() << ": " << *srange.begin() << '\n'; // Ausgabe: 1: 7
multiset msrange( in.begin(), in.end() );      // multiset erhält doppelte
cout <<= msrange; // Ausgabe: 7 7 7 7 7 7 7

Listing 24.70: Die »multiset«-Suchfunktionen finden den Bereich der passenden Elemente.

Book listing lst-0786-book.cpp:

// https://godbolt.org/z/9hPqa5MfY 
#include <string>
#include <iterator> // distance
#include <ranges>   // subrange
struct Person {
  std::string name;
  friend bool operator<(const Person &a, const Person &b) {  
    // nur erster Buchstabe
    return a.name.size()==0 ? true
      : (b.name.size()==0 ? false : a.name[0] < b.name[0]);
  }
};
// …
multiset data{ 1, 4,4, 2,2,2, 7, 9 };
auto [von1, bis1] = data.equal_range(2);
cout << "Anzahl 2en: "
  << std::distance(von1, bis1) << '\n'; // Ausgabe: Anzahl 2en: 3
auto [von2, bis2] = data.equal_range(5);
cout << "Anzahl 5en: "
  << std::distance(von2, bis2) << '\n'; // Ausgabe: Anzahl 5en: 0
multiset<Person> raum{
  {"Karl"}, {"Kurt"}, {"Peter"}, {"Karl"}, {"Ken"}};
auto [p, q] = raum.equal_range(Person{"K"});
for(auto& p : std::ranges::subrange(p,q)) { // C++20-Range oder einfache Schleife
  cout << p.name << ' ';
}
cout << '\n'; // Ausgabe: Karl Kurt Karl Ken

Godbolt Listing lst-0786-godb.cpp, https://godbolt.org/z/9hPqa5MfY:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9hPqa5MfY 
#include <string>
#include <iterator> // distance
#include <ranges>   // subrange
struct Person {
  std::string name;
  friend bool operator<(const Person &a, const Person &b) {  
    // nur erster Buchstabe
    return a.name.size()==0 ? true
      : (b.name.size()==0 ? false : a.name[0] < b.name[0]);
  }
};
// …
multiset data{ 1, 4,4, 2,2,2, 7, 9 };
auto [von1, bis1] = data.equal_range(2);
cout << "Anzahl 2en: "
  << std::distance(von1, bis1) << '\n'; // Ausgabe: Anzahl 2en: 3
auto [von2, bis2] = data.equal_range(5);
cout << "Anzahl 5en: "
  << std::distance(von2, bis2) << '\n'; // Ausgabe: Anzahl 5en: 0
multiset<Person> raum{
  {"Karl"}, {"Kurt"}, {"Peter"}, {"Karl"}, {"Ken"}};
auto [p, q] = raum.equal_range(Person{"K"});
for(auto& p : std::ranges::subrange(p,q)) { // C++20-Range oder einfache Schleife
  cout << p.name << ' ';
}
cout << '\n'; // Ausgabe: Karl Kurt Karl Ken

Listing 24.71: Dies ist die Schablone für die Listings dieses Abschnitts zur »multimap«.

Book listing lst-0787-book.cpp:

// https://godbolt.org/z/sfaEozjzq 
#include <map>        // die Hauptsache
#include <iostream>   // zur Ausgabe
#include <string>     // gerne mal Schlüssel oder Ziel
using std::multimap; using std::cout; using std::string;
template<typename Key, typename Trg, typename Cmp>
std::ostream& operator<<=(std::ostream&os, const multimap<Key,Trg,Cmp>&data){
    for(auto &e : data) {
        os << e.first << ":" << e.second << ' ';
    }
    return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
   // Beispielcode hier
}

Godbolt Listing lst-0787-godb.cpp, https://godbolt.org/z/sfaEozjzq:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sfaEozjzq 
#include <map>        // die Hauptsache
#include <iostream>   // zur Ausgabe
#include <string>     // gerne mal Schlüssel oder Ziel
using std::multimap; using std::cout; using std::string;
template<typename Key, typename Trg, typename Cmp>
std::ostream& operator<<=(std::ostream&os, const multimap<Key,Trg,Cmp>&data){
    for(auto &e : data) {
        os << e.first << ":" << e.second << ' ';
    }
    return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
   // Beispielcode hier
}

Listing 24.72: Es landen alle Einträge in der »multimap«.

Book listing lst-0788-book.cpp:

// https://godbolt.org/z/6no9dW64d 
multimap int2int{ std::make_pair(3,4) };  // multimap<int,int>
using namespace std::literals; // für ""s
multimap<int,string> numlang{
    {7,"sieben"s}, {6,"six"s},
    {7,"siete"s}, {6,"sechs"s},
    {7,"seven"s}, {7,"yedi"s},
    {8,"eight"s} };
cout <<= numlang; // Ausgabe: 6:six 6:sechs 7:sieben 7:siete 7:seven 7:yedi 8:eight

Godbolt Listing lst-0788-godb.cpp, https://godbolt.org/z/6no9dW64d:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6no9dW64d 
multimap int2int{ std::make_pair(3,4) };  // multimap<int,int>
using namespace std::literals; // für ""s
multimap<int,string> numlang{
    {7,"sieben"s}, {6,"six"s},
    {7,"siete"s}, {6,"sechs"s},
    {7,"seven"s}, {7,"yedi"s},
    {8,"eight"s} };
cout <<= numlang; // Ausgabe: 6:six 6:sechs 7:sieben 7:siete 7:seven 7:yedi 8:eight

Listing 24.73: »insert« und »emplace« bei der »multimap«

Book listing lst-0789-book.cpp:

// https://godbolt.org/z/dj68ej97r 
using namespace std::literals; // für ""s

multimap<int,string> numlang{};
numlang.insert( std::make_pair(7, "seven"s) );
numlang.insert( std::pair<int,string>(7, "sieben"s) );
numlang.emplace( 7, "yedi"s );
cout <<= numlang; // Ausgabe: 7:seven 7:sieben 7:yedi

Godbolt Listing lst-0789-godb.cpp, https://godbolt.org/z/dj68ej97r:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dj68ej97r 
using namespace std::literals; // für ""s

multimap<int,string> numlang{};
numlang.insert( std::make_pair(7, "seven"s) );
numlang.insert( std::pair<int,string>(7, "sieben"s) );
numlang.emplace( 7, "yedi"s );
cout <<= numlang; // Ausgabe: 7:seven 7:sieben 7:yedi

Listing 24.74: »erase«mit einem Schlüssel kann mehrere Elemente löschen.

Book listing lst-0790-book.cpp:

// https://godbolt.org/z/TbvKTn4Px 
multimap<char,int> vals{ {'c',1}, {'c',8}, {'g',1},
    {'c',1}, {'a',7}, {'a',1}, {'c',2}, };
cout <<= vals;            // Ausgabe: a:7 a:1 c:1 c:8 c:1 c:2 g:1
vals.erase( 'c' );        // löscht alle 'c's
cout <<= vals;            // Ausgabe: a:7 a:1 g:1
vals.erase(vals.begin()); // löscht nur eines der 'a's
cout <<= vals;            // Ausgabe: a:1 g:1

Godbolt Listing lst-0790-godb.cpp, https://godbolt.org/z/TbvKTn4Px:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TbvKTn4Px 
multimap<char,int> vals{ {'c',1}, {'c',8}, {'g',1},
    {'c',1}, {'a',7}, {'a',1}, {'c',2}, };
cout <<= vals;            // Ausgabe: a:7 a:1 c:1 c:8 c:1 c:2 g:1
vals.erase( 'c' );        // löscht alle 'c's
cout <<= vals;            // Ausgabe: a:7 a:1 g:1
vals.erase(vals.begin()); // löscht nur eines der 'a's
cout <<= vals;            // Ausgabe: a:1 g:1

Listing 24.75: Betreiben Sie ungeordnete assoziative Container niemals mit einer schlechten Hashfunktion.

Book listing lst-0791-book.cpp:

// https://godbolt.org/z/ejMv4ohse 
#include <set>               // set, multiset
#include <unordered_set>     // unordered_set, unordered_multiset
#include <iostream>
#include <string>
#include <chrono>            // Zeitmessung
using std::cout;
using namespace std::chrono;

long long millisSeit(steady_clock::time_point start) {
    return duration_cast<milliseconds>(steady_clock::now()-start).count();
}
constexpr size_t ITERATIONS = 100'000;
template<typename Cont, typename Gen>
    requires std::invocable<Gen, size_t> &&  // C++20-Concept
    requires(Gen gen, size_t n) {{gen(n)} -> std::same_as<int>;} &&
    std::same_as<typename Cont::value_type,int>
void timeStuff(std::string name, Cont data, Gen genNum) {
    cout << name << "...";
    auto start = steady_clock::now();
    for(size_t idx=0; idx<ITERATIONS; ++idx) {
        data.insert( genNum(idx) );
    }
    cout << " " << millisSeit(start) << " ms" << std::endl;
}
int alleGleich(size_t) { return 7; }      // erzeugt immer die gleiche Zahl
int gestreut(size_t n) { return int(n); } // erzeugt unterschiedliche Zahlen
struct BadHash {  // die schlechtestmögliche Hashfunktion als Funktor
       size_t   operator()(int) const { return 1uz; }
};

int main() {
   std::multiset<int> m{};
   timeStuff("multiset           alleGleich        ", m, &alleGleich);
   timeStuff("multiset           gestreut          ", m, &gestreut);
   std::set<int> s{};
   timeStuff("set                alleGleich        ", s, &alleGleich);
   timeStuff("set                gestreut          ", s, &gestreut);
   std::unordered_multiset<int> um{};
   timeStuff("unordered_multiset alleGleich        ", um, &alleGleich);
   timeStuff("unordered_multiset gestreut          ", um, &gestreut);
   std::unordered_multiset<int,BadHash> umb{};
   timeStuff("unordered_multiset alleGleich badHash", umb, &alleGleich);
   timeStuff("unordered_multiset gestreut   badHash", umb, &gestreut);
}

Godbolt Listing lst-0791-godb.cpp, https://godbolt.org/z/ejMv4ohse:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ejMv4ohse 
#include <set>               // set, multiset
#include <unordered_set>     // unordered_set, unordered_multiset
#include <iostream>
#include <string>
#include <chrono>            // Zeitmessung
using std::cout;
using namespace std::chrono;

long long millisSeit(steady_clock::time_point start) {
    return duration_cast<milliseconds>(steady_clock::now()-start).count();
}
constexpr size_t ITERATIONS = 100'000;
template<typename Cont, typename Gen>
    requires std::invocable<Gen, size_t> &&  // C++20-Concept
    requires(Gen gen, size_t n) {{gen(n)} -> std::same_as<int>;} &&
    std::same_as<typename Cont::value_type,int>
void timeStuff(std::string name, Cont data, Gen genNum) {
    cout << name << "...";
    auto start = steady_clock::now();
    for(size_t idx=0; idx<ITERATIONS; ++idx) {
        data.insert( genNum(idx) );
    }
    cout << " " << millisSeit(start) << " ms" << std::endl;
}
int alleGleich(size_t) { return 7; }      // erzeugt immer die gleiche Zahl
int gestreut(size_t n) { return int(n); } // erzeugt unterschiedliche Zahlen
struct BadHash {  // die schlechtestmögliche Hashfunktion als Funktor
       size_t   operator()(int) const { return 1uz; }
};

int main() {
   std::multiset<int> m{};
   timeStuff("multiset           alleGleich        ", m, &alleGleich);
   timeStuff("multiset           gestreut          ", m, &gestreut);
   std::set<int> s{};
   timeStuff("set                alleGleich        ", s, &alleGleich);
   timeStuff("set                gestreut          ", s, &gestreut);
   std::unordered_multiset<int> um{};
   timeStuff("unordered_multiset alleGleich        ", um, &alleGleich);
   timeStuff("unordered_multiset gestreut          ", um, &gestreut);
   std::unordered_multiset<int,BadHash> umb{};
   timeStuff("unordered_multiset alleGleich badHash", umb, &alleGleich);
   timeStuff("unordered_multiset gestreut   badHash", umb, &gestreut);
}

Listing 24.76: Doppelt so viele Elemente bei schlechter Hashfunktion heißt viermal länger.

Book listing lst-0792-book.cpp:

// https://godbolt.org/z/osdTM7vbx 
#include <unordered_set>     // unordered_set, unordered_multiset
#include <iostream>
#include <string>
#include <chrono>            // Zeitmessung
using std::cout;
using namespace std::chrono;
long long millisSeit(steady_clock::time_point start) {
    return duration_cast<milliseconds>(steady_clock::now()-start)
        .count();
}
struct BadHash {  // die schlechtestmögliche Hashfunktion als Funktor
    size_t   operator()(int) const { return 1uz; }
};
void timeStuff(size_t iters) {
    std::unordered_multiset<int,BadHash> data{};
    cout << iters << "...";
    auto start = steady_clock::now();
    for(size_t idx=0; idx<iters; ++idx) {
        data.insert( (int)idx );
    }
    cout << " " << millisSeit(start) << " ms" << std::endl;
}
constexpr size_t LIMIT = 20'000;
int main() {
    size_t iters = 100;
    while(iters < LIMIT) {
        timeStuff(iters);
        iters *= 2; // verdoppeln
    }
}

Godbolt Listing lst-0792-godb.cpp, https://godbolt.org/z/osdTM7vbx:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/osdTM7vbx 
#include <unordered_set>     // unordered_set, unordered_multiset
#include <iostream>
#include <string>
#include <chrono>            // Zeitmessung
using std::cout;
using namespace std::chrono;
long long millisSeit(steady_clock::time_point start) {
    return duration_cast<milliseconds>(steady_clock::now()-start)
        .count();
}
struct BadHash {  // die schlechtestmögliche Hashfunktion als Funktor
    size_t   operator()(int) const { return 1uz; }
};
void timeStuff(size_t iters) {
    std::unordered_multiset<int,BadHash> data{};
    cout << iters << "...";
    auto start = steady_clock::now();
    for(size_t idx=0; idx<iters; ++idx) {
        data.insert( (int)idx );
    }
    cout << " " << millisSeit(start) << " ms" << std::endl;
}
constexpr size_t LIMIT = 20'000;
int main() {
    size_t iters = 100;
    while(iters < LIMIT) {
        timeStuff(iters);
        iters *= 2; // verdoppeln
    }
}

Listing 24.77: Dies ist die Schablone für die Beispiellistings zu »unordered_set«.

Book listing lst-0793-book.cpp:

// https://godbolt.org/z/xv6vrcsY6 
#include <unordered_set>
#include <iostream>
using std::unordered_set; using std::cout; using std::ostream;
template<typename Elem, typename Cmp>
ostream& operator<<=(ostream&os, const unordered_set<Elem,Cmp>&data){
    for(auto &e : data) {
        os << e << ' ';
    }
    return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
   // Beispielcode hier
}

Godbolt Listing lst-0793-godb.cpp, https://godbolt.org/z/xv6vrcsY6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xv6vrcsY6 
#include <unordered_set>
#include <iostream>
using std::unordered_set; using std::cout; using std::ostream;
template<typename Elem, typename Cmp>
ostream& operator<<=(ostream&os, const unordered_set<Elem,Cmp>&data){
    for(auto &e : data) {
        os << e << ' ';
    }
    return os << '\n'; // '<<=' statt '<<' für Zeilenumbruch
}
int main() {
   // Beispielcode hier
}

Listing 24.78: Ein »unordered_set« mit eigenem Vergleich und Hashfunktion

Book listing lst-0794-book.cpp:

// https://godbolt.org/z/MWrY1cznd 
#include <unordered_set>
#include <iostream>
#include <vector>
#include <string>
using std::string; using std::unordered_set; using std::cout;
struct Word {
    string word_;
    size_t row_;
    Word(const string &word, size_t row)
        : word_{word}, row_{row} {}
    friend bool operator==(const Word& a, const Word &b)
        { return a.word_ == b.word_; } // ignoriert row
 };
 namespace std {
 template<> struct hash<Word> { // ignoriert row
        std::hash<string> stringHash;
        std::size_t operator()(const Word &w) const {
            return stringHash(w.word_);
        }
 }; }
 struct ExactWordHash { // bezieht row mit ein
     std::hash<string> sHash;
     std::hash<size_t> iHash;
     bool operator()(const Word& a) const {
         return sHash(a.word_) ^ iHash(a.row_);
     }
 };
 struct ExactWordEqual { // bezieht row mit ein
     bool operator()(const Word& a, const Word &b) const {
         return std::tie(a.word_, a.row_) == std::tie(b.word_, b.row_);
     }
 };
 int main() {
     std::vector input {
       Word{"eine",0}, Word{"Rose",0},
       Word{"ist",1}, Word{"eine",1}, Word{"Rose",1},
       Word{"ist",2}, Word{"eine",2}, Word{"Rose",2},  };
     // Überladungen nutzen
     unordered_set<Word> words( input.begin(), input.end() );
     cout << words.size() << '\n'; // Ausgabe: 3
     // Eigene Funktoren nutzen
     unordered_set<Word,ExactWordHash,ExactWordEqual> poem(
          input.begin(), input.end() );
     cout << poem.size() << '\n';  // Ausgabe: 8
     // Hash als Lambda
     auto h = [](const auto &a) { return std::hash<string>{}(a.word_); };
     unordered_set<Word,decltype(h)> rose(input.begin(), input.end(), 10, h);
     cout << rose.size() << '\n';  // Ausgabe: 3
 }

Godbolt Listing lst-0794-godb.cpp, https://godbolt.org/z/MWrY1cznd:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MWrY1cznd 
#include <unordered_set>
#include <iostream>
#include <vector>
#include <string>
using std::string; using std::unordered_set; using std::cout;
struct Word {
    string word_;
    size_t row_;
    Word(const string &word, size_t row)
        : word_{word}, row_{row} {}
    friend bool operator==(const Word& a, const Word &b)
        { return a.word_ == b.word_; } // ignoriert row
 };
 namespace std {
 template<> struct hash<Word> { // ignoriert row
        std::hash<string> stringHash;
        std::size_t operator()(const Word &w) const {
            return stringHash(w.word_);
        }
 }; }
 struct ExactWordHash { // bezieht row mit ein
     std::hash<string> sHash;
     std::hash<size_t> iHash;
     bool operator()(const Word& a) const {
         return sHash(a.word_) ^ iHash(a.row_);
     }
 };
 struct ExactWordEqual { // bezieht row mit ein
     bool operator()(const Word& a, const Word &b) const {
         return std::tie(a.word_, a.row_) == std::tie(b.word_, b.row_);
     }
 };
 int main() {
     std::vector input {
       Word{"eine",0}, Word{"Rose",0},
       Word{"ist",1}, Word{"eine",1}, Word{"Rose",1},
       Word{"ist",2}, Word{"eine",2}, Word{"Rose",2},  };
     // Überladungen nutzen
     unordered_set<Word> words( input.begin(), input.end() );
     cout << words.size() << '\n'; // Ausgabe: 3
     // Eigene Funktoren nutzen
     unordered_set<Word,ExactWordHash,ExactWordEqual> poem(
          input.begin(), input.end() );
     cout << poem.size() << '\n';  // Ausgabe: 8
     // Hash als Lambda
     auto h = [](const auto &a) { return std::hash<string>{}(a.word_); };
     unordered_set<Word,decltype(h)> rose(input.begin(), input.end(), 10, h);
     cout << rose.size() << '\n';  // Ausgabe: 3
 }

Listing 24.79: Dies sind die Möglichkeiten, ein »unordered_set« zu initialisieren.

Book listing lst-0796-book.cpp:

// https://godbolt.org/z/WeMr9ePdh 
#include <set>
template<typename Key>
std::set<Key> sorted(const unordered_set<Key> &data)
  { return std::set<Key>(data.begin(), data.end()); }
// …
// ohne Argumente
unordered_set<int> leer{};
cout <<= leer;      // Ausgabe:
// Initialisierungsliste
unordered_set daten{1,1,2,2,3,3,4,4,5,5};// doppelte werden nicht übernommen
cout <<= daten;     // Ausgabe in etwa: 5 4 3 2 1
// Kopie
unordered_set kopie(daten);
cout <<= kopie;     // Ausgabe in etwa: 5 4 3 2 1
// Bereich
auto so1 = sorted(daten);
unordered_set bereich(std::next(so1.begin()), std::prev(so1.end()));
cout <<= bereich;   // Ausgabe in etwa: 2 3 4

Godbolt Listing lst-0796-godb.cpp, https://godbolt.org/z/WeMr9ePdh:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WeMr9ePdh 
#include <set>
template<typename Key>
std::set<Key> sorted(const unordered_set<Key> &data)
  { return std::set<Key>(data.begin(), data.end()); }
// …
// ohne Argumente
unordered_set<int> leer{};
cout <<= leer;      // Ausgabe:
// Initialisierungsliste
unordered_set daten{1,1,2,2,3,3,4,4,5,5};// doppelte werden nicht übernommen
cout <<= daten;     // Ausgabe in etwa: 5 4 3 2 1
// Kopie
unordered_set kopie(daten);
cout <<= kopie;     // Ausgabe in etwa: 5 4 3 2 1
// Bereich
auto so1 = sorted(daten);
unordered_set bereich(std::next(so1.begin()), std::prev(so1.end()));
cout <<= bereich;   // Ausgabe in etwa: 2 3 4

Listing 24.80: Einfügen in ein »unordered_set«

Book listing lst-0797-book.cpp:

// https://godbolt.org/z/KEb55ds4z 
unordered_set<int> data;
auto res1 = data.insert( 5 );                  // Einfügen per Kopie
if(res1.second) cout << "ja, 5 nun drin\n";    // das klappt
auto res2 = data.emplace( 5 );                 // Einfügen vor Ort
if(res2.second) cout << "zweite 5 nun drin\n"; // das klappt nicht
auto res3 = data.insert(res1.first, 6 );       // mit Positionshinweis
// res3 ist nur ein iterator ohne bool
cout << *res3 << '\n';                         // auf jeden Fall eine 6

Godbolt Listing lst-0797-godb.cpp, https://godbolt.org/z/KEb55ds4z:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KEb55ds4z 
unordered_set<int> data;
auto res1 = data.insert( 5 );                  // Einfügen per Kopie
if(res1.second) cout << "ja, 5 nun drin\n";    // das klappt
auto res2 = data.emplace( 5 );                 // Einfügen vor Ort
if(res2.second) cout << "zweite 5 nun drin\n"; // das klappt nicht
auto res3 = data.insert(res1.first, 6 );       // mit Positionshinweis
// res3 ist nur ein iterator ohne bool
cout << *res3 << '\n';                         // auf jeden Fall eine 6

Listing 24.81: Löschen erhält die Reihenfolge der restlichen Elemente.

Book listing lst-0798-book.cpp:

// https://godbolt.org/z/1s41eaWjx 
unordered_set nums{ 1,2,3,4,5,6,7,8,9,10 };
cout <<= nums;               // Ausgabe ähnlich: 9 1 2 3 4 5 6 7 8 10
auto it = nums.begin();
while(it != nums.end()) {
    if(*it % 2 == 0) {       // gerade Zahl?
        it = nums.erase(it); // Restelemente verändern nicht Reihenfolge
    } else {
        ++it;
    }
}
cout <<= nums;               // Ausgabe ähnlich: 9 1 3 5 7

Godbolt Listing lst-0798-godb.cpp, https://godbolt.org/z/1s41eaWjx:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1s41eaWjx 
unordered_set nums{ 1,2,3,4,5,6,7,8,9,10 };
cout <<= nums;               // Ausgabe ähnlich: 9 1 2 3 4 5 6 7 8 10
auto it = nums.begin();
while(it != nums.end()) {
    if(*it % 2 == 0) {       // gerade Zahl?
        it = nums.erase(it); // Restelemente verändern nicht Reihenfolge
    } else {
        ++it;
    }
}
cout <<= nums;               // Ausgabe ähnlich: 9 1 3 5 7

Listing 24.82: Sie können eimerweise auf »unordered_set« zugreifen.

Book listing lst-0799-book.cpp:

// https://godbolt.org/z/TTbY8YbG9 
// Befüllen mit 100 Werten
unordered_set<int> d{};
d.rehash(10);             // versuche, 10 Eimer zu haben
d.max_load_factor(100.0); // 100 Elemente pro Eimer sind okay
cout << "Eimer Anzahl: " << d.bucket_count() << '\n';
for(int x : std::ranges::iota_view{0,100}) { // C++20 iota(): 0,1,2,…,99
    d.insert(x);
}
// ausgeben
for(int b = d.bucket_count()-1; b>=0; --b) {
    cout << "Eimer "<<b<<":";
    for(auto it=d.begin(b); it!=d.end(b); ++it)
        cout << *it << ' ';
    cout << '\n';
}

Godbolt Listing lst-0799-godb.cpp, https://godbolt.org/z/TTbY8YbG9:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TTbY8YbG9 
// Befüllen mit 100 Werten
unordered_set<int> d{};
d.rehash(10);             // versuche, 10 Eimer zu haben
d.max_load_factor(100.0); // 100 Elemente pro Eimer sind okay
cout << "Eimer Anzahl: " << d.bucket_count() << '\n';
for(int x : std::ranges::iota_view{0,100}) { // C++20 iota(): 0,1,2,…,99
    d.insert(x);
}
// ausgeben
for(int b = d.bucket_count()-1; b>=0; --b) {
    cout << "Eimer "<<b<<":";
    for(auto it=d.begin(b); it!=d.end(b); ++it)
        cout << *it << ' ';
    cout << '\n';
}

Listing 24.83: Dies ist die Schablone für die Beispiellistings zu »unordered_map«.

Book listing lst-0800-book.cpp:

// https://godbolt.org/z/ffashhsK1 
#include <unordered_map>
#include <iostream>
using std::unordered_map; using std::cout;
template<typename K, typename T>
std::ostream& operator<<=(std::ostream&os, const unordered_map<K,T>&data) {
    for(auto &e : data) {
        os << e.first << ":" << e.second << ' ';
    }
    return os << '\n'; // bei operator<<= mit Zeilenumbruch
}
int main() {
   // Beispielcode hier
}

Godbolt Listing lst-0800-godb.cpp, https://godbolt.org/z/ffashhsK1:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ffashhsK1 
#include <unordered_map>
#include <iostream>
using std::unordered_map; using std::cout;
template<typename K, typename T>
std::ostream& operator<<=(std::ostream&os, const unordered_map<K,T>&data) {
    for(auto &e : data) {
        os << e.first << ":" << e.second << ' ';
    }
    return os << '\n'; // bei operator<<= mit Zeilenumbruch
}
int main() {
   // Beispielcode hier
}

Listing 24.84: Ein eigener Datentyp als Schlüssel in einer »unordered_map«

Book listing lst-0801-book.cpp:

// https://godbolt.org/z/Ka3czrn54 
#include <unordered_map>
#include <iostream>
#include <string>
using std::string; using std::unordered_map; using std::cout;
struct Stadt {
    string name_;
    explicit Stadt(const string &name) : name_{name} {}
    auto operator<=>(const Stadt &b) const = default;
 };
 struct StadtHash {
     std::hash<string> sHash;
     size_t operator()(const Stadt& a) const {
         return sHash(a.name_);
     }
 };
 int main() {
     unordered_map<Stadt,string,StadtHash> abk{
         {Stadt{"Bielefeld"}, "BI"},
         {Stadt{"Jetzendorf"}, "JE"},
         {Stadt{"Tharandt"}, "TH"},
         };
     cout << abk[Stadt{"Bielefeld"}] << '\n'; // Ausgabe: BI
 }

Godbolt Listing lst-0801-godb.cpp, https://godbolt.org/z/Ka3czrn54:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Ka3czrn54 
#include <unordered_map>
#include <iostream>
#include <string>
using std::string; using std::unordered_map; using std::cout;
struct Stadt {
    string name_;
    explicit Stadt(const string &name) : name_{name} {}
    auto operator<=>(const Stadt &b) const = default;
 };
 struct StadtHash {
     std::hash<string> sHash;
     size_t operator()(const Stadt& a) const {
         return sHash(a.name_);
     }
 };
 int main() {
     unordered_map<Stadt,string,StadtHash> abk{
         {Stadt{"Bielefeld"}, "BI"},
         {Stadt{"Jetzendorf"}, "JE"},
         {Stadt{"Tharandt"}, "TH"},
         };
     cout << abk[Stadt{"Bielefeld"}] << '\n'; // Ausgabe: BI
 }

Listing 24.85: Sie können auch nur einen Teil Ihres Objekts als Schlüssel verwenden.

Book listing lst-0802-book.cpp:

// https://godbolt.org/z/eTYqbedqK 
#include <unordered_set> // unordered_multiset
#include <iostream>
#include <string>
using std::string; using std::unordered_multiset; using std::cout;
struct Stadt {
    string name_;
    explicit Stadt(const string &name) : name_{name} {}
    auto operator<=>(const Stadt &b) const = default;
 };
 struct Eintrag { string stadt_; int plz_; };
 struct EqEintrag {
     bool operator()(const Eintrag&a, const Eintrag&b) const {
         return a.stadt_==b.stadt_;
     }
 };
 struct HashEintrag {
     std::hash<string> sHash;
     size_t operator()(const Eintrag& a) const {
         return sHash(a.stadt_);
     }
 };
 int main() {
     unordered_multiset<Eintrag,HashEintrag,EqEintrag> verzeichnis{
         {Eintrag{"Bielefeld", 33615}},
         {Eintrag{"Bielefeld", 33617}},
         {Eintrag{"Bielefeld", 33621}},
         {Eintrag{"Berlin", 10032}},
         {Eintrag{"Berlin", 10027}},
         };
     const Eintrag such{"Bielefeld", 0}; // plz spielt bei Suche keine Rolle
     cout<<"Bielefeld hat "<<verzeichnis.count(such)<<" Postleitzahlen.\n";
     cout<<"Die Postleitzahlen von Bielefeld sind:\n";
     auto [wo, bis] = verzeichnis.equal_range(such);
     while(wo != bis) {
         cout << "  " << wo->plz_ << '\n';
         ++wo;
     }
 }

Godbolt Listing lst-0802-godb.cpp, https://godbolt.org/z/eTYqbedqK:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eTYqbedqK 
#include <unordered_set> // unordered_multiset
#include <iostream>
#include <string>
using std::string; using std::unordered_multiset; using std::cout;
struct Stadt {
    string name_;
    explicit Stadt(const string &name) : name_{name} {}
    auto operator<=>(const Stadt &b) const = default;
 };
 struct Eintrag { string stadt_; int plz_; };
 struct EqEintrag {
     bool operator()(const Eintrag&a, const Eintrag&b) const {
         return a.stadt_==b.stadt_;
     }
 };
 struct HashEintrag {
     std::hash<string> sHash;
     size_t operator()(const Eintrag& a) const {
         return sHash(a.stadt_);
     }
 };
 int main() {
     unordered_multiset<Eintrag,HashEintrag,EqEintrag> verzeichnis{
         {Eintrag{"Bielefeld", 33615}},
         {Eintrag{"Bielefeld", 33617}},
         {Eintrag{"Bielefeld", 33621}},
         {Eintrag{"Berlin", 10032}},
         {Eintrag{"Berlin", 10027}},
         };
     const Eintrag such{"Bielefeld", 0}; // plz spielt bei Suche keine Rolle
     cout<<"Bielefeld hat "<<verzeichnis.count(such)<<" Postleitzahlen.\n";
     cout<<"Die Postleitzahlen von Bielefeld sind:\n";
     auto [wo, bis] = verzeichnis.equal_range(such);
     while(wo != bis) {
         cout << "  " << wo->plz_ << '\n';
         ++wo;
     }
 }

GodboltId:9szMGYK9v

Book listing lst-0804-book.cpp:

// https://godbolt.org/z/9szMGYK9v 
struct EqEintrag {
    bool operator()(const Eintrag&a, const Eintrag&b) const {
        return a.stadt_==b.stadt_;
    }
};

struct HashEintrag {
    std::hash<string> sHash;
    std::hash<int> iHash;
    size_t operator()(const Eintrag& a) const {
        return sHash(a.stadt_) ^ iHash(a.plz_); //                                          (ERR)  zu viele Elemente
    }
};

Godbolt Listing lst-0804-godb.cpp, https://godbolt.org/z/9szMGYK9v:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9szMGYK9v 
struct EqEintrag {
    bool operator()(const Eintrag&a, const Eintrag&b) const {
        return a.stadt_==b.stadt_;
    }
};

struct HashEintrag {
    std::hash<string> sHash;
    std::hash<int> iHash;
    size_t operator()(const Eintrag& a) const {
        return sHash(a.stadt_) ^ iHash(a.plz_); //                                          (ERR)  zu viele Elemente
    }
};

Listing 24.86: Dies sind die Möglichkeiten, ein »unordered_multiset« zu initialisieren.

Book listing lst-0805-book.cpp:

// https://godbolt.org/z/qnove9h8o 
#include <unordered_set> // unordered_multiset
#include <vector>
#include <iostream>
using std::unordered_multiset; using std::cout; using std::ostream;
template<typename Elem>
ostream& operator<<=(ostream&os, const unordered_multiset<Elem>&data) {
    for(auto &e : data) { os << e << ' '; } return os << '\n'; }
int main() {
    // ohne Argumente
    unordered_multiset<int> leer(1000); // anfängliche Größe der Hashtabelle
    cout <<= leer;      // Ausgabe:
    // Initialisierungsliste; doppelte werden übernommen:
    unordered_multiset daten{ 1,1,2,2,3,3,4,4,5,5 };
    cout <<= daten;     // Ausgabe in etwa: 5 5 4 4 3 3 2 2 1 1
    // Kopie
    unordered_multiset kopie(daten);
    cout <<= kopie;     // Ausgabe in etwa: 5 5 4 4 3 3 2 2 1 1
    // Bereich
    std::vector in{1,2,3,10,20,30,10,20,30,1,2,3};
    unordered_multiset bereich(in.begin()+3, in.end()-3);
    cout <<= bereich;   // Ausgabe in etwa: 30 30 20 20 10 10
}

Godbolt Listing lst-0805-godb.cpp, https://godbolt.org/z/qnove9h8o:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qnove9h8o 
#include <unordered_set> // unordered_multiset
#include <vector>
#include <iostream>
using std::unordered_multiset; using std::cout; using std::ostream;
template<typename Elem>
ostream& operator<<=(ostream&os, const unordered_multiset<Elem>&data) {
    for(auto &e : data) { os << e << ' '; } return os << '\n'; }
int main() {
    // ohne Argumente
    unordered_multiset<int> leer(1000); // anfängliche Größe der Hashtabelle
    cout <<= leer;      // Ausgabe:
    // Initialisierungsliste; doppelte werden übernommen:
    unordered_multiset daten{ 1,1,2,2,3,3,4,4,5,5 };
    cout <<= daten;     // Ausgabe in etwa: 5 5 4 4 3 3 2 2 1 1
    // Kopie
    unordered_multiset kopie(daten);
    cout <<= kopie;     // Ausgabe in etwa: 5 5 4 4 3 3 2 2 1 1
    // Bereich
    std::vector in{1,2,3,10,20,30,10,20,30,1,2,3};
    unordered_multiset bereich(in.begin()+3, in.end()-3);
    cout <<= bereich;   // Ausgabe in etwa: 30 30 20 20 10 10
}

Listing 24.87: Bei den »multi«-Varianten ergibt »count« richtig Sinn.

Book listing lst-0806-book.cpp:

// https://godbolt.org/z/a8cGxr9s9 
#include <unordered_set> // unordered_multiset
#include <iostream>
#include <string>
using std::unordered_multiset; using std::cout; using std::string;
int main() {
    const string in = "Keines meiner beiden Beine zeigt einen Schein.";
    unordered_multiset<int> cs(in.begin(), in.end()); // string als Container
    cout << cs.count( 'e' ) << " Mal e\n"; // Ausgabe: 10 Mal e
}

Godbolt Listing lst-0806-godb.cpp, https://godbolt.org/z/a8cGxr9s9:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a8cGxr9s9 
#include <unordered_set> // unordered_multiset
#include <iostream>
#include <string>
using std::unordered_multiset; using std::cout; using std::string;
int main() {
    const string in = "Keines meiner beiden Beine zeigt einen Schein.";
    unordered_multiset<int> cs(in.begin(), in.end()); // string als Container
    cout << cs.count( 'e' ) << " Mal e\n"; // Ausgabe: 10 Mal e
}

Listing 24.88: Adapter funktionieren mit wechselbaren Implementierungen.

Book listing lst-0807-book.cpp:

// https://godbolt.org/z/qaKv6Tebf 
#include <stack>
void run(auto data) { /* ... */ }  // C++20, abgekürztes Funktionstemplate
run(stack<int>{});              // Default: nutzt vector<int>
run(stack<int,vector<int>>{});  // wie der Default
run(stack<int,list<int>>{});    // nutzt list<int>

Godbolt Listing lst-0807-godb.cpp, https://godbolt.org/z/qaKv6Tebf:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qaKv6Tebf 
#include <stack>
void run(auto data) { /* ... */ }  // C++20, abgekürztes Funktionstemplate
run(stack<int>{});              // Default: nutzt vector<int>
run(stack<int,vector<int>>{});  // wie der Default
run(stack<int,list<int>>{});    // nutzt list<int>

Listing 24.89: »string« eignet sich besser für Texte als »vector«.

Book listing lst-0808-book.cpp:

// https://godbolt.org/z/6sYGnqnTj 
#include <vector>
#include <string>
#include <iostream>
#include <string_view>
using std::string; using std::string_view; using std::vector; using std::cout;
int get_len(string_view str) { return str.size(); } // string_view als Parameter
int main() {
    string s1 = "Hallo";                  // einfach mit Stringliteral
    string s2{'H','a','l','l','o'};       // oder mit Liste von char
    using namespace std::literals;        // für ""s-Suffix und ""sv-Suffix
    auto s3 = "Hallo"s;  // noch einfacher mit echtem Stringliteral
    vector<char> v1{"Hallo"};             //                          (ERR)  kein vector mit Stringliteral
    vector<char> v2{'H','a','l','l','o'}; // Liste von char ist okay
    cout << s1 << s2 << s3 << '\n';       // Ausgabe von string geht
    cout << v1 << v2 << '\n';             //                          (ERR)  vector hat keine Ausgabe
    const auto str = "String"s;           // Stringliteral
    const auto strv = "String-View"sv;    // String-View-Literal
    cout << "Laenge von 'str' ist " << get_len(str) << '\n';   // Ausgabe: … 6
    cout << "Laenge von 'strv' ist " << get_len(strv) << '\n'; // Ausgabe: … 11
}

Godbolt Listing lst-0808-godb.cpp, https://godbolt.org/z/6sYGnqnTj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6sYGnqnTj 
#include <vector>
#include <string>
#include <iostream>
#include <string_view>
using std::string; using std::string_view; using std::vector; using std::cout;
int get_len(string_view str) { return str.size(); } // string_view als Parameter
int main() {
    string s1 = "Hallo";                  // einfach mit Stringliteral
    string s2{'H','a','l','l','o'};       // oder mit Liste von char
    using namespace std::literals;        // für ""s-Suffix und ""sv-Suffix
    auto s3 = "Hallo"s;  // noch einfacher mit echtem Stringliteral
    vector<char> v1{"Hallo"};             //                          (ERR)  kein vector mit Stringliteral
    vector<char> v2{'H','a','l','l','o'}; // Liste von char ist okay
    cout << s1 << s2 << s3 << '\n';       // Ausgabe von string geht
    cout << v1 << v2 << '\n';             //                          (ERR)  vector hat keine Ausgabe
    const auto str = "String"s;           // Stringliteral
    const auto strv = "String-View"sv;    // String-View-Literal
    cout << "Laenge von 'str' ist " << get_len(str) << '\n';   // Ausgabe: … 6
    cout << "Laenge von 'strv' ist " << get_len(strv) << '\n'; // Ausgabe: … 11
}

Listing 24.90: »bitset« im Beispiel

Book listing lst-0809-book.cpp:

// https://godbolt.org/z/jrGdT6665 
#include <bitset>
#include <iostream>
using std::cout;
int main() {
    std::bitset<8> bits{};         // 8 Bit dicht gepackt
    bits.set(4);                   // 5. Bit auf 1
    cout << bits << '\n';          // 00010000
    bits.flip();                   // alle Bits invertieren
    cout << bits << '\n';          // 11101111
    bits.set();                    // alle Bits auf 1
    bits.flip(1);                  // 2. Bit invertieren
    std::cout << bits << '\n';     // 11111101
    bits.reset();                  // alle Bits auf 0
    bits.set(4);                   // 5. Bit auf 1
    cout << bits << '\n';          // 00010000
    bits.flip();                   // alle Bits invertieren
    cout << bits << '\n';          // 11101111
    bits.set();                    // alle Bits auf 1
    bits.flip(1);                  // 2. Bit invertieren
    bits.flip(6);                  // 7. Bit invertieren
    cout << bits << '\n';          // 10111101
    // Verknüpfungen
    std::bitset<8> zack("....####", 8, '.', '#');
    cout << zack << '\n';          // 00001111
    cout << (bits & zack) << '\n'; // 00001101
    cout << (bits | zack) << '\n'; // 10111111
    cout << (bits ^ zack) << '\n'; // 10110010
    // andere Integertypen
    std::bitset<64> b(0x123456789abcdef0LL);
    cout << b << '\n';
    // 0001001000110100010101100111100010011010101111001101111011110000
    cout << std::hex << b.to_ullong() << '\n'; // umwandeln
    // 123456789abcdef0
}

Godbolt Listing lst-0809-godb.cpp, https://godbolt.org/z/jrGdT6665:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jrGdT6665 
#include <bitset>
#include <iostream>
using std::cout;
int main() {
    std::bitset<8> bits{};         // 8 Bit dicht gepackt
    bits.set(4);                   // 5. Bit auf 1
    cout << bits << '\n';          // 00010000
    bits.flip();                   // alle Bits invertieren
    cout << bits << '\n';          // 11101111
    bits.set();                    // alle Bits auf 1
    bits.flip(1);                  // 2. Bit invertieren
    std::cout << bits << '\n';     // 11111101
    bits.reset();                  // alle Bits auf 0
    bits.set(4);                   // 5. Bit auf 1
    cout << bits << '\n';          // 00010000
    bits.flip();                   // alle Bits invertieren
    cout << bits << '\n';          // 11101111
    bits.set();                    // alle Bits auf 1
    bits.flip(1);                  // 2. Bit invertieren
    bits.flip(6);                  // 7. Bit invertieren
    cout << bits << '\n';          // 10111101
    // Verknüpfungen
    std::bitset<8> zack("....####", 8, '.', '#');
    cout << zack << '\n';          // 00001111
    cout << (bits & zack) << '\n'; // 00001101
    cout << (bits | zack) << '\n'; // 10111111
    cout << (bits ^ zack) << '\n'; // 10110010
    // andere Integertypen
    std::bitset<64> b(0x123456789abcdef0LL);
    cout << b << '\n';
    // 0001001000110100010101100111100010011010101111001101111011110000
    cout << std::hex << b.to_ullong() << '\n'; // umwandeln
    // 123456789abcdef0
}

GodboltId:KPP16bdK9

Book listing lst-0810-book.cpp:

// https://godbolt.org/z/KPP16bdK9 
#include <iostream>
#include <valarray>
using std::ostream; using std::valarray;
ostream& operator<<(ostream&os, const valarray<double>&vs) {
    os << "[";
    for(auto&v : vs) os << v << " ";
    return os << "]";
}
int main() {
    valarray a{ 1.0, 2.0, 3.0, 4.0 }; // valarray<double>
    valarray b{ 2.0, 4.0, 6.0, 8.0 };
    valarray c{ 2.5, 1.75, 0.5, 0.125 };
    valarray<double> x = ( a + b ) * c;
    std::cout << "x: " << x << "\n";  // Ausgabe: [7.5 10.5 4.5 1.5 ]
    auto y = ( a + b ) / 2;           // y ist nicht unbedingt ein valarray!
    std::cout << "y: " << y << "\n";  // Ausgabe: [1.5 3 4.5 6 ]
}

Godbolt Listing lst-0810-godb.cpp, https://godbolt.org/z/KPP16bdK9:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KPP16bdK9 
#include <iostream>
#include <valarray>
using std::ostream; using std::valarray;
ostream& operator<<(ostream&os, const valarray<double>&vs) {
    os << "[";
    for(auto&v : vs) os << v << " ";
    return os << "]";
}
int main() {
    valarray a{ 1.0, 2.0, 3.0, 4.0 }; // valarray<double>
    valarray b{ 2.0, 4.0, 6.0, 8.0 };
    valarray c{ 2.5, 1.75, 0.5, 0.125 };
    valarray<double> x = ( a + b ) * c;
    std::cout << "x: " << x << "\n";  // Ausgabe: [7.5 10.5 4.5 1.5 ]
    auto y = ( a + b ) / 2;           // y ist nicht unbedingt ein valarray!
    std::cout << "y: " << y << "\n";  // Ausgabe: [1.5 3 4.5 6 ]
}

GodboltId:r11584Wef

Book listing lst-0811-book.cpp:

// https://godbolt.org/z/r11584Wef 
#include <valarray>
#include <iostream>
using namespace std;
template<typename T>
ostream& operator<<=(ostream &os, const valarray<T>& a) { // '<<=' mit Newline
    for(const auto &v : a) os << v << ' ';
    return os << '\n';
}
int main() {
    // … Beispielcode hier …
}

Godbolt Listing lst-0811-godb.cpp, https://godbolt.org/z/r11584Wef:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/r11584Wef 
#include <valarray>
#include <iostream>
using namespace std;
template<typename T>
ostream& operator<<=(ostream &os, const valarray<T>& a) { // '<<=' mit Newline
    for(const auto &v : a) os << v << ' ';
    return os << '\n';
}
int main() {
    // … Beispielcode hier …
}

GodboltId:WGazqoGc1

Book listing lst-0812-book.cpp:

// https://godbolt.org/z/WGazqoGc1 
valarray<int> data;              // zunächst Größe 0
cout << data.size() << "\n";     // Ausgabe: 0
data.resize(100);                // vergrößert
cout << data.size() << "\n";     // Ausgabe: 100
valarray<int> data2(200);        // Platz für 200 Werte
cout << data2.size() << "\n";    // Ausgabe: 200
valarray<int> dataC(5, 20);      // zwanzig 5en, andersherum als bei vector
cout << dataC.size() <<": dataC[6]="<< dataC[6]<< "\n"; // Ausgabe: 20: dataC[6]=5
valarray dataD{ 2, 3, 5, 7, 11 };      // valarray<int>, Initialisierungsliste
cout << dataD.size() <<": dataD[3]=" <<dataD[3]<< "\n"; // Ausgabe: 5: dataD[3]=7

Godbolt Listing lst-0812-godb.cpp, https://godbolt.org/z/WGazqoGc1:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WGazqoGc1 
valarray<int> data;              // zunächst Größe 0
cout << data.size() << "\n";     // Ausgabe: 0
data.resize(100);                // vergrößert
cout << data.size() << "\n";     // Ausgabe: 100
valarray<int> data2(200);        // Platz für 200 Werte
cout << data2.size() << "\n";    // Ausgabe: 200
valarray<int> dataC(5, 20);      // zwanzig 5en, andersherum als bei vector
cout << dataC.size() <<": dataC[6]="<< dataC[6]<< "\n"; // Ausgabe: 20: dataC[6]=5
valarray dataD{ 2, 3, 5, 7, 11 };      // valarray<int>, Initialisierungsliste
cout << dataD.size() <<": dataD[3]=" <<dataD[3]<< "\n"; // Ausgabe: 5: dataD[3]=7

GodboltId:dd1q6GdYq

Book listing lst-0813-book.cpp:

// https://godbolt.org/z/dd1q6GdYq 
valarray v { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
valarray<int> r1(v[slice(0, 4, 3)]); // Start bei 0, 4 Elemente, Schrittweite 3
cout <<= r1;                         // Ausgabe: 1 4 7 10
valarray<int> r2(v[v > 6]);          // adressiert per valarray<bool>
cout <<= r2;                         // Ausgabe: 7 8 9 10 11 12
const valarray<size_t> indirekt{ 2, 2, 3, 6 };  // doppelte erlaubt
valarray<int> r5(v[indirekt]);       // adressiert per valarray<size_t>
cout <<= r5;                         // Ausgabe: 3 3 4 7

Godbolt Listing lst-0813-godb.cpp, https://godbolt.org/z/dd1q6GdYq:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dd1q6GdYq 
valarray v { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
valarray<int> r1(v[slice(0, 4, 3)]); // Start bei 0, 4 Elemente, Schrittweite 3
cout <<= r1;                         // Ausgabe: 1 4 7 10
valarray<int> r2(v[v > 6]);          // adressiert per valarray<bool>
cout <<= r2;                         // Ausgabe: 7 8 9 10 11 12
const valarray<size_t> indirekt{ 2, 2, 3, 6 };  // doppelte erlaubt
valarray<int> r5(v[indirekt]);       // adressiert per valarray<size_t>
cout <<= r5;                         // Ausgabe: 3 3 4 7

GodboltId:6z6d71Ka4

Book listing lst-0814-book.cpp:

// https://godbolt.org/z/6z6d71Ka4 
valarray<int> v {
  1,  2,  3,
  4,  5,  6,
  7,  8,  9,
 10, 11, 12 };
v[slice(0, 4, 3)] *= valarray<int>(v[slice(0, 4, 3)]); // erste Spalte quadrieren
cout <<= v;  // Ausgabe: 1 2 3 16 5 6 49 8 9 100 11 12
v[slice(0, 4, 3)] = valarray<int>{1, 4, 7, 10}; // wiederherstellen
valarray<int> r3(v[gslice(0, {2, 3}, {6,2})]);  // 2-D-Schnitt vom 3-D-Würfel
cout <<= r3;                                    // Ausgabe: 1 3 5 7 9 11
valarray<char> text("jetzt gehts erst los", 20);
valarray<char> caps("JGEL", 4);
valarray<size_t> idx{ 0, 6, 12, 17 };           // Indexe in text
text[idx] = caps;                               // indirekt zuweisen
cout <<= text;                                  // Ausgabe: Jetzt Gehts Erst Los

Godbolt Listing lst-0814-godb.cpp, https://godbolt.org/z/6z6d71Ka4:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6z6d71Ka4 
valarray<int> v {
  1,  2,  3,
  4,  5,  6,
  7,  8,  9,
 10, 11, 12 };
v[slice(0, 4, 3)] *= valarray<int>(v[slice(0, 4, 3)]); // erste Spalte quadrieren
cout <<= v;  // Ausgabe: 1 2 3 16 5 6 49 8 9 100 11 12
v[slice(0, 4, 3)] = valarray<int>{1, 4, 7, 10}; // wiederherstellen
valarray<int> r3(v[gslice(0, {2, 3}, {6,2})]);  // 2-D-Schnitt vom 3-D-Würfel
cout <<= r3;                                    // Ausgabe: 1 3 5 7 9 11
valarray<char> text("jetzt gehts erst los", 20);
valarray<char> caps("JGEL", 4);
valarray<size_t> idx{ 0, 6, 12, 17 };           // Indexe in text
text[idx] = caps;                               // indirekt zuweisen
cout <<= text;                                  // Ausgabe: Jetzt Gehts Erst Los

GodboltId:jr1chqbze

Book listing lst-0815-book.cpp:

// https://godbolt.org/z/jr1chqbze 
#include <iostream>
#include <iomanip> // setw
#include <valarray>
using namespace std;

/* Matrix drucken */
template<class T>
void printMatrix(ostream&os, const valarray<T>& a, size_t n) {
    for(size_t i = 0; i < (n*n); ++i) {
        os << setw(3) << a[i];        // Wert drucken
        os << ((i+1)%n ? ' ' : '\n'); // nächste Zeile?
    }
}

/* Matrix-Kreuzprodukt */
template<class T>

valarray<T> matmult(
        const valarray<T>& a, size_t arows, size_t acols,
        const valarray<T>& b, size_t brows, size_t bcols)
{
    /* Bedingung: acols==brows */
    valarray<T> result(arows * bcols);
    for(size_t i = 0; i < arows; ++i) {
      for(size_t j = 0; j < bcols; ++j) {
        auto row = a[slice(acols*i, acols, 1)]; // Zeile
        auto col = b[slice(j, brows, bcols)];   // Spalte
        result[i*bcols+j] = (row*col).sum();    // Kreuzprodukt Zeile a[i] und 
                                                // Spalte b[j]
      }
    }
    return result;
}

int main() {
    constexpr int n = 3;
    valarray ma{1,0,-1,  2,2,-3,  3,4,0};         // 3 x 3-Matrix
    valarray mb{3,4,-1,  1,-3,0,  -1,1,2};        // 3 x 3-Matrix
    printMatrix(cout, ma, n);
    cout << "  -mal-\n ";
    printMatrix(cout, mb, n);
    cout << "  -ergibt-:\n ";
    valarray<int> mc = matmult(ma, n,n, mb, n,n);
    printMatrix(cout, mc, n);
}

Godbolt Listing lst-0815-godb.cpp, https://godbolt.org/z/jr1chqbze:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jr1chqbze 
#include <iostream>
#include <iomanip> // setw
#include <valarray>
using namespace std;

/* Matrix drucken */
template<class T>
void printMatrix(ostream&os, const valarray<T>& a, size_t n) {
    for(size_t i = 0; i < (n*n); ++i) {
        os << setw(3) << a[i];        // Wert drucken
        os << ((i+1)%n ? ' ' : '\n'); // nächste Zeile?
    }
}

/* Matrix-Kreuzprodukt */
template<class T>

valarray<T> matmult(
        const valarray<T>& a, size_t arows, size_t acols,
        const valarray<T>& b, size_t brows, size_t bcols)
{
    /* Bedingung: acols==brows */
    valarray<T> result(arows * bcols);
    for(size_t i = 0; i < arows; ++i) {
      for(size_t j = 0; j < bcols; ++j) {
        auto row = a[slice(acols*i, acols, 1)]; // Zeile
        auto col = b[slice(j, brows, bcols)];   // Spalte
        result[i*bcols+j] = (row*col).sum();    // Kreuzprodukt Zeile a[i] und 
                                                // Spalte b[j]
      }
    }
    return result;
}

int main() {
    constexpr int n = 3;
    valarray ma{1,0,-1,  2,2,-3,  3,4,0};         // 3 x 3-Matrix
    valarray mb{3,4,-1,  1,-3,0,  -1,1,2};        // 3 x 3-Matrix
    printMatrix(cout, ma, n);
    cout << "  -mal-\n ";
    printMatrix(cout, mb, n);
    cout << "  -ergibt-:\n ";
    valarray<int> mc = matmult(ma, n,n, mb, n,n);
    printMatrix(cout, mc, n);
}

Listing 25.1: Mit dem Eingabevektor wird etwas gemacht, aber was?

Book listing lst-0816-book.cpp:

// https://godbolt.org/z/5czT3xoxc 
std::vector v{0,1,3,5,7,9,2,4,6,8};
bool flag = true;
for(size_t i=1; (i <= v.size()) && flag; ++i) {
    flag = false;
    for(size_t j=0; (j < v.size()-1); ++j) {
        if(v[j+1] < v[j]) {
            std::swap(v[j+1], v[j]);
            flag = true;
        }
    }
}
for(int i:v) std::cout << i << ' ';

Godbolt Listing lst-0816-godb.cpp, https://godbolt.org/z/5czT3xoxc:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5czT3xoxc 
std::vector v{0,1,3,5,7,9,2,4,6,8};
bool flag = true;
for(size_t i=1; (i <= v.size()) && flag; ++i) {
    flag = false;
    for(size_t j=0; (j < v.size()-1); ++j) {
        if(v[j+1] < v[j]) {
            std::swap(v[j+1], v[j]);
            flag = true;
        }
    }
}
for(int i:v) std::cout << i << ' ';

Listing 25.2: Dieser Eingabevektor wird sortiert!

Book listing lst-0817-book.cpp:

// https://godbolt.org/z/EjT7nPPv7 
std::vector v{0,1,3,5,7,9,2,4,6,8};
std::sort(v.begin(), v.end());
for(int i:v) std::cout << i << ' ';
std::cout << '\n';
// oder mit einer Range:
std::ranges::sort(v);
for(int i:v) std::cout << i << ' ';
std::cout << '\n';

Godbolt Listing lst-0817-godb.cpp, https://godbolt.org/z/EjT7nPPv7:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/EjT7nPPv7 
std::vector v{0,1,3,5,7,9,2,4,6,8};
std::sort(v.begin(), v.end());
for(int i:v) std::cout << i << ' ';
std::cout << '\n';
// oder mit einer Range:
std::ranges::sort(v);
for(int i:v) std::cout << i << ' ';
std::cout << '\n';

Listing 25.3: Zusammenstecken von Funktionen

Book listing lst-0818-book.cpp:

// https://godbolt.org/z/9xrP8Ehvd 
#include <algorithm>
#include <vector>
#include <iostream>
void sort_uniq(std::vector<int> &data) {
    std::ranges::sort(data);                        // sortieren
    auto to_delete = std::ranges::unique(data);     // nach hinten verschieben
    data.erase(to_delete.begin(), to_delete.end()); // tatsächlich löschen
}
int main() {
    std::vector ns{1,5,2,3,9,2,2,2,2,1,5,2,2,3,1,1,2,2,1};
    sort_uniq(ns);
    std::ranges::for_each(ns, [](auto x) {
        std::cout << x << ' '; });
    std::cout << '\n'; // Ausgabe: 1 2 3 5 9
}

Godbolt Listing lst-0818-godb.cpp, https://godbolt.org/z/9xrP8Ehvd:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9xrP8Ehvd 
#include <algorithm>
#include <vector>
#include <iostream>
void sort_uniq(std::vector<int> &data) {
    std::ranges::sort(data);                        // sortieren
    auto to_delete = std::ranges::unique(data);     // nach hinten verschieben
    data.erase(to_delete.begin(), to_delete.end()); // tatsächlich löschen
}
int main() {
    std::vector ns{1,5,2,3,9,2,2,2,2,1,5,2,2,3,1,1,2,2,1};
    sort_uniq(ns);
    std::ranges::for_each(ns, [](auto x) {
        std::cout << x << ' '; });
    std::cout << '\n'; // Ausgabe: 1 2 3 5 9
}

Listing 25.4: Algorithmen laufen parallel

Book listing lst-0819-book.cpp:

// https://godbolt.org/z/qcT9o7YfG 
#include <algorithm>  // find
#include <numeric>    // reduce, accumulate
#include <execution>  // std::execution
#include <iostream>
#include <chrono>     // Zeitmessung
using namespace std::chrono;
long long millisSeit(steady_clock::time_point start) {
    return duration_cast<milliseconds>(steady_clock::now()-start).count();
}
template <typename FUNC> void timeit(const char* title, FUNC func) {
    auto start = steady_clock::now();
    auto ret = func(); // ausführen
    std::cout << title << ": " << millisSeit(start) << " ms" << std::endl;
}
int main() {
    using namespace std::execution;          // seq, par, par_unseq
    using std::reduce; using std::accumulate; using std::find;
    std::vector<double> v(600'000'000, 0.0); // 600 Millionen Elemente
    for(auto&x:v) x = ::rand();              // mit Zufallswerten füllen
    timeit("warmlaufen       ", [&v] {
        return reduce(seq, v.begin(), v.end(), 0.0);
    });
    timeit("accumulate       ", [&v] {
        return accumulate(v.begin(), v.end(), 0.0);
    });
    timeit("reduce, seq      ", [&v] {
        return reduce(seq, v.begin(), v.end(), 0.0);
    });
    timeit("reduce, par      ", [&v] {
        return reduce(par, v.begin(), v.end(), 0.0);
    });

    timeit("reduce, par_unseq", [&v] {
        return reduce(par_unseq, v.begin(), v.end(), 0.0);
    });
    timeit("find, seq        ", [&v] {
        return find(seq, v.begin(), v.end(), 1.1) == v.end() ? 0.0 : 1.0;
    });
    timeit("find, par        ", [&v] {
        return find(par, v.begin(), v.end(), 1.1) == v.end() ? 0.0 : 1.0;
    });
    return 0;
}

Godbolt Listing lst-0819-godb.cpp, https://godbolt.org/z/qcT9o7YfG:

//#(compile) c++; compiler:g112; options:-O3 -std=c++23 -ltbb; libs:tbb@trunk
// https://godbolt.org/z/qcT9o7YfG 
#include <algorithm>  // find
#include <numeric>    // reduce, accumulate
#include <execution>  // std::execution
#include <iostream>
#include <chrono>     // Zeitmessung
using namespace std::chrono;
long long millisSeit(steady_clock::time_point start) {
    return duration_cast<milliseconds>(steady_clock::now()-start).count();
}
template <typename FUNC> void timeit(const char* title, FUNC func) {
    auto start = steady_clock::now();
    auto ret = func(); // ausführen
    std::cout << title << ": " << millisSeit(start) << " ms" << std::endl;
}
int main() {
    using namespace std::execution;          // seq, par, par_unseq
    using std::reduce; using std::accumulate; using std::find;
    std::vector<double> v(600'000'000, 0.0); // 600 Millionen Elemente
    for(auto&x:v) x = ::rand();              // mit Zufallswerten füllen
    timeit("warmlaufen       ", [&v] {
        return reduce(seq, v.begin(), v.end(), 0.0);
    });
    timeit("accumulate       ", [&v] {
        return accumulate(v.begin(), v.end(), 0.0);
    });
    timeit("reduce, seq      ", [&v] {
        return reduce(seq, v.begin(), v.end(), 0.0);
    });
    timeit("reduce, par      ", [&v] {
        return reduce(par, v.begin(), v.end(), 0.0);
    });

    timeit("reduce, par_unseq", [&v] {
        return reduce(par_unseq, v.begin(), v.end(), 0.0);
    });
    timeit("find, seq        ", [&v] {
        return find(seq, v.begin(), v.end(), 1.1) == v.end() ? 0.0 : 1.0;
    });
    timeit("find, par        ", [&v] {
        return find(par, v.begin(), v.end(), 1.1) == v.end() ? 0.0 : 1.0;
    });
    return 0;
}

Listing 25.5: View-Typen und ihre Adapter

Book listing lst-0820-book.cpp:

// https://godbolt.org/z/rrq1v5qPs 
std::list lst{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto take5 = rs::take_view{lst, 5};     // View via Typ
auto take6 = lst | vs::take(6);         // View via Adapter

Godbolt Listing lst-0820-godb.cpp, https://godbolt.org/z/rrq1v5qPs:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rrq1v5qPs 
std::list lst{1, 2, 3, 4, 5, 6, 7, 8, 9};
auto take5 = rs::take_view{lst, 5};     // View via Typ
auto take6 = lst | vs::take(6);         // View via Adapter

Listing 25.6: Besonders die C++23-Views lassen sich gut kombinieren.

Book listing lst-0821-book.cpp:

// https://godbolt.org/z/hYTv6f9eo 
#include <ranges>
#include <array>
#include <string>
#include <iostream>
#include <string_view>
using namespace std::literals; using namespace std;

// Funktion für die Ausgabe von allem Möglichen
template <typename OBJ>
void print(OBJ&& obj, int level = 0) {
  if constexpr(std::ranges::input_range<OBJ>) {                 // range
    cout << '[';
    for (const auto& elem : obj) print(elem, level+1);
    cout << ']';
  } else if constexpr(requires (OBJ tpl){ std::get<0>(tpl);}) { // tuple/pair
    cout << "(";
    print(get<0>(obj), level+1); print(get<1>(obj), level+1);
    cout << ")";
  } else cout << obj;                                           // element
  if (level == 0) cout << '\n';
}
int main() {
  using namespace std::views; // ausnahmsweise für die Kürze
  auto const nums = array{0, 0, 1, 1, 2, 2};
  auto const animals = array{"cat"s, "dog"s};
  print(iota(0, 5) | chunk(2));                      // Ausgabe: [[01][23][4]]
  print(nums | chunk_by(equal_to{}));                // Ausgabe: [[00][11][22]]
  print(iota(0, 5) | slide(3));                      // Ausgabe: [[012][123][234]]
  print(iota(0, 10) | stride(3));                    // Ausgabe: [0369]
  print(repeat(8) |take(5));                         // Ausgabe: [88888]
  print(zip_transform(plus{}, nums, nums));          // Ausgabe: [002244]
  print(zip(iota(0, 3), iota(1, 4)));                // Ausgabe: [(01)(12)(23)]
  print(iota(0, 4) | adjacent<2>);                   // Ausgabe: [(01)(12)(23)]
  print(iota(0, 4) | pairwise);                      // Ausgabe: [(01)(12)(23)]
  print(iota(0, 4) | adjacent_transform<2>(plus{})); // Ausgabe: [135]
  print(iota(0, 4) | pairwise_transform(plus{}));    // Ausgabe: [135]
  print(animals | join_with( '+' ));                 // Ausgabe: [cat+dog]
  print(cartesian_product(iota(0, 2), "AZ"s));       // Ausgabe: [(0A)(0Z)(1A)(1Z)]
  print(enumerate("APL"s));                          // Ausgabe: [(0A)(1P)(2L)]
  return 0;
}

Godbolt Listing lst-0821-godb.cpp, https://godbolt.org/z/hYTv6f9eo:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hYTv6f9eo 
#include <ranges>
#include <array>
#include <string>
#include <iostream>
#include <string_view>
using namespace std::literals; using namespace std;

// Funktion für die Ausgabe von allem Möglichen
template <typename OBJ>
void print(OBJ&& obj, int level = 0) {
  if constexpr(std::ranges::input_range<OBJ>) {                 // range
    cout << '[';
    for (const auto& elem : obj) print(elem, level+1);
    cout << ']';
  } else if constexpr(requires (OBJ tpl){ std::get<0>(tpl);}) { // tuple/pair
    cout << "(";
    print(get<0>(obj), level+1); print(get<1>(obj), level+1);
    cout << ")";
  } else cout << obj;                                           // element
  if (level == 0) cout << '\n';
}
int main() {
  using namespace std::views; // ausnahmsweise für die Kürze
  auto const nums = array{0, 0, 1, 1, 2, 2};
  auto const animals = array{"cat"s, "dog"s};
  print(iota(0, 5) | chunk(2));                      // Ausgabe: [[01][23][4]]
  print(nums | chunk_by(equal_to{}));                // Ausgabe: [[00][11][22]]
  print(iota(0, 5) | slide(3));                      // Ausgabe: [[012][123][234]]
  print(iota(0, 10) | stride(3));                    // Ausgabe: [0369]
  print(repeat(8) |take(5));                         // Ausgabe: [88888]
  print(zip_transform(plus{}, nums, nums));          // Ausgabe: [002244]
  print(zip(iota(0, 3), iota(1, 4)));                // Ausgabe: [(01)(12)(23)]
  print(iota(0, 4) | adjacent<2>);                   // Ausgabe: [(01)(12)(23)]
  print(iota(0, 4) | pairwise);                      // Ausgabe: [(01)(12)(23)]
  print(iota(0, 4) | adjacent_transform<2>(plus{})); // Ausgabe: [135]
  print(iota(0, 4) | pairwise_transform(plus{}));    // Ausgabe: [135]
  print(animals | join_with( '+' ));                 // Ausgabe: [cat+dog]
  print(cartesian_product(iota(0, 2), "AZ"s));       // Ausgabe: [(0A)(0Z)(1A)(1Z)]
  print(enumerate("APL"s));                          // Ausgabe: [(0A)(1P)(2L)]
  return 0;
}

Listing 25.7: Funktionen müssen einen Range-Parameter als universelle Referenz bekommen.

Book listing lst-0824-book.cpp:

// https://godbolt.org/z/64zdMEe4r 
void print(const auto& range) { //             (ERR)  kritisch: konstante Referenz
  for (auto const& e : range) { cout << e; } cout << '\n';
}
vector vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
list   lst{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
print(vec);                  // funktioniert auf direkten Containern
print(lst);                  // funktioniert auf direkten Containern
print(vec | vs::take(3));    // take mit vector klappt
print(lst | vs::take(3));    // take mit list klappt
print(vec | vs::drop(5));    // drop mit vector klappt
print(lst | vs::drop(5));    //             (ERR)  drop mit list klappt nicht!

Godbolt Listing lst-0824-godb.cpp, https://godbolt.org/z/64zdMEe4r:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/64zdMEe4r 
void print(const auto& range) { //             (ERR)  kritisch: konstante Referenz
  for (auto const& e : range) { cout << e; } cout << '\n';
}
vector vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
list   lst{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
print(vec);                  // funktioniert auf direkten Containern
print(lst);                  // funktioniert auf direkten Containern
print(vec | vs::take(3));    // take mit vector klappt
print(lst | vs::take(3));    // take mit list klappt
print(vec | vs::drop(5));    // drop mit vector klappt
print(lst | vs::drop(5));    //             (ERR)  drop mit list klappt nicht!

Listing 25.8: Eine Funktion nur für Views und nicht für Container

Book listing lst-0825-book.cpp:

// https://godbolt.org/z/s1GjfWxv6 
void print(ranges::view auto range) { // Wertparameter, eingeschränkt auf Views
  for (auto const& e : range) { cout << e; } cout << '\n';
}
vector vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
list   lst{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
print(vec);                      //             (ERR)  Verboten für Container, sehr gut!
print(vs::all(vec));             // Container in View umwandeln
print(vs::all(lst));             // Container in View umwandeln
print(vec | vs::take(3));        // take mit vector klappt
print(lst | vs::take(3));        // take mit list klappt
print(vec | vs::drop(5));        // drop mit vector klappt
print(lst | vs::drop(5));        // als Wertparameter klappt drop mit list

Godbolt Listing lst-0825-godb.cpp, https://godbolt.org/z/s1GjfWxv6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/s1GjfWxv6 
void print(ranges::view auto range) { // Wertparameter, eingeschränkt auf Views
  for (auto const& e : range) { cout << e; } cout << '\n';
}
vector vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
list   lst{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
print(vec);                      //             (ERR)  Verboten für Container, sehr gut!
print(vs::all(vec));             // Container in View umwandeln
print(vs::all(lst));             // Container in View umwandeln
print(vec | vs::take(3));        // take mit vector klappt
print(lst | vs::take(3));        // take mit list klappt
print(vec | vs::drop(5));        // drop mit vector klappt
print(lst | vs::drop(5));        // als Wertparameter klappt drop mit list

Listing 25.9: Suchen mit Prädikat

Book listing lst-0826-book.cpp:

// https://godbolt.org/z/3r5E1f9YP 
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
#include <ranges>
using std::vector; using std::string; using std::string_view;
using namespace std::literals; using std::find_if;
vector<string> demo_split(string_view s) {
  vector<string> result{};
  auto it = s.begin();
  while(it != s.end()) {
    // bis normales Zeichen:
    it = find_if(it, s.end(), [](char c) { return c!=' '; });
     // bis Leerzeichen:
     auto jt = find_if(it, s.end(), [](char c) { return c==' '; });
    if(it!=s.end())
      result.push_back(string(it, jt)); // Kopie ins Ergebnis
    it = jt;
  }
  return result;
}
int main() {
  auto text = "Der Text ist kurz"sv;
  auto res = demo_split(text);
  std::ranges::for_each(res, [](const string &e) {
      std::cout << "[" << e << "] "; });
  std::cout << '\n'; // Ausgabe: [Der] [Text] [ist] [kurz]
  // oder gleich mit views::split:
  for(auto word : text | std::views::split(" "sv)) {
    std::cout << "[";
    for(auto c : word) std::cout << c;
    std::cout << "] ";
  } // Ausgabe: [Der] [Text] [ist] [kurz]
}

Godbolt Listing lst-0826-godb.cpp, https://godbolt.org/z/3r5E1f9YP:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3r5E1f9YP 
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
#include <ranges>
using std::vector; using std::string; using std::string_view;
using namespace std::literals; using std::find_if;
vector<string> demo_split(string_view s) {
  vector<string> result{};
  auto it = s.begin();
  while(it != s.end()) {
    // bis normales Zeichen:
    it = find_if(it, s.end(), [](char c) { return c!=' '; });
     // bis Leerzeichen:
     auto jt = find_if(it, s.end(), [](char c) { return c==' '; });
    if(it!=s.end())
      result.push_back(string(it, jt)); // Kopie ins Ergebnis
    it = jt;
  }
  return result;
}
int main() {
  auto text = "Der Text ist kurz"sv;
  auto res = demo_split(text);
  std::ranges::for_each(res, [](const string &e) {
      std::cout << "[" << e << "] "; });
  std::cout << '\n'; // Ausgabe: [Der] [Text] [ist] [kurz]
  // oder gleich mit views::split:
  for(auto word : text | std::views::split(" "sv)) {
    std::cout << "[";
    for(auto c : word) std::cout << c;
    std::cout << "] ";
  } // Ausgabe: [Der] [Text] [ist] [kurz]
}

Listing 25.10: Ein Palindrom mit einer Codezeile erkennen

Book listing lst-0827-book.cpp:

// https://godbolt.org/z/WqvM6KEEM 
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
using std::string_view; using namespace std::literals; using std::cout;
auto istPalindrom(string_view sv) {
  return std::ranges::equal(sv.begin(), sv.end(), sv.rbegin(), sv.rend()); };
int main() {
  for(auto s : {"regallager"sv, "rentner"sv, "blutwurst"sv }) {
    cout << s << " ist " << (istPalindrom(s)?"ein":"kein") << " Palindrom\n";
  }
}

Godbolt Listing lst-0827-godb.cpp, https://godbolt.org/z/WqvM6KEEM:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WqvM6KEEM 
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
using std::string_view; using namespace std::literals; using std::cout;
auto istPalindrom(string_view sv) {
  return std::ranges::equal(sv.begin(), sv.end(), sv.rbegin(), sv.rend()); };
int main() {
  for(auto s : {"regallager"sv, "rentner"sv, "blutwurst"sv }) {
    cout << s << " ist " << (istPalindrom(s)?"ein":"kein") << " Palindrom\n";
  }
}

Listing 25.11: Auch »nur lesende« Algorithmen wie »for_each« können die Elemente verändern.

Book listing lst-0828-book.cpp:

// https://godbolt.org/z/jz1Gqo7d9 
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
    std::vector<int> c{ 1,2,3,4 };
    std::ranges::for_each(c, [](auto &n) { n*=n; }); //             (ERR)  modifizierend
    std::cout << c[3] << '\n'; // Ausgabe: 16
}

Godbolt Listing lst-0828-godb.cpp, https://godbolt.org/z/jz1Gqo7d9:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jz1Gqo7d9 
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
    std::vector<int> c{ 1,2,3,4 };
    std::ranges::for_each(c, [](auto &n) { n*=n; }); //             (ERR)  modifizierend
    std::cout << c[3] << '\n'; // Ausgabe: 16
}

Listing 25.12: »transform« kann mit unterschiedlichen Typen jonglieren.

Book listing lst-0830-book.cpp:

// https://godbolt.org/z/7r4b8jdGr 
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
using std::to_string; using std::string; using std::vector;
struct Squares {
    mutable int n = 1;
    int operator()() const { return n*n++; }
};
int main() {
    vector<int> sq(10);
    std::ranges::generate(sq, Squares{});
    std::ranges::for_each(sq, [](auto n) {
        std::cout << n << " "; });
    std::cout << '\n';        // Ausgabe: 1 4 9 16 25 36 49 64 81 100
    string a = "NCC-";
    vector<int> b {1,7,0,1};
    vector<string> c(4);
    auto f = [](char c, int i) -> string { return c+to_string(i); };
    std::ranges::transform(
        a,           // Eingabe 1
        b,           // Eingabe 2
        c.begin(),   // Ausgabe
        f);          // string f(char,int)
    std::ranges::for_each(c, [](auto s) {
        std::cout << s << " "; });
    std::cout << '\n';        // Ausgabe: N1 C7 C0 -1
}

Godbolt Listing lst-0830-godb.cpp, https://godbolt.org/z/7r4b8jdGr:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7r4b8jdGr 
#include <algorithm>
#include <iostream>
#include <vector>
#include <string>
using std::to_string; using std::string; using std::vector;
struct Squares {
    mutable int n = 1;
    int operator()() const { return n*n++; }
};
int main() {
    vector<int> sq(10);
    std::ranges::generate(sq, Squares{});
    std::ranges::for_each(sq, [](auto n) {
        std::cout << n << " "; });
    std::cout << '\n';        // Ausgabe: 1 4 9 16 25 36 49 64 81 100
    string a = "NCC-";
    vector<int> b {1,7,0,1};
    vector<string> c(4);
    auto f = [](char c, int i) -> string { return c+to_string(i); };
    std::ranges::transform(
        a,           // Eingabe 1
        b,           // Eingabe 2
        c.begin(),   // Ausgabe
        f);          // string f(char,int)
    std::ranges::for_each(c, [](auto s) {
        std::cout << s << " "; });
    std::cout << '\n';        // Ausgabe: N1 C7 C0 -1
}

Listing 25.13: Mit Range-Adaptern transformieren

Book listing lst-0831-book.cpp:

// https://godbolt.org/z/j9ozax8qE 
#include <ranges> // zip_transform
// …
auto res = std::views::zip_transform(f, a, b);  // Range-Adapter
for(auto s: res) { std::cout << s << " "; };
std::cout << '\n';        // Ausgabe: N1 C7 C0 -1

Godbolt Listing lst-0831-godb.cpp, https://godbolt.org/z/j9ozax8qE:

//#(compile) c++; compiler:g132; options:"-std=c++23"; libs:-
// https://godbolt.org/z/j9ozax8qE 
#include <ranges> // zip_transform
// …
auto res = std::views::zip_transform(f, a, b);  // Range-Adapter
for(auto s: res) { std::cout << s << " "; };
std::cout << '\n';        // Ausgabe: N1 C7 C0 -1

GodboltId:s53qx664K

Book listing lst-0832-book.cpp:

// https://godbolt.org/z/s53qx664K 
#include <iostream>
#include <random>       // default_random_engine
#include <string>
#include <iterator>     // back_inserter
#include <algorithm>    // sample

int main() {
   std::default_random_engine zufall{};
   const std::string in = "abcdefgh";
   for(auto idx : {0,1,2,3}) {
     std::string out;
     std::ranges::sample(in, std::back_inserter(out), 5, zufall);
     std::cout << out << '\n';
   }
}

Godbolt Listing lst-0832-godb.cpp, https://godbolt.org/z/s53qx664K:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/s53qx664K 
#include <iostream>
#include <random>       // default_random_engine
#include <string>
#include <iterator>     // back_inserter
#include <algorithm>    // sample

int main() {
   std::default_random_engine zufall{};
   const std::string in = "abcdefgh";
   for(auto idx : {0,1,2,3}) {
     std::string out;
     std::ranges::sample(in, std::back_inserter(out), 5, zufall);
     std::cout << out << '\n';
   }
}

Listing 25.14: Wirkungsweise der Mischmengenalgorithmen

Book listing lst-0833-book.cpp:

// https://godbolt.org/z/qW4hvE9s3 
#include <algorithm>
#include <iostream>
#include <list>
#include <string>
#include <iterator> // ostream_iterator
#include <cctype>   // toupper
using std::toupper;
int main() {
    std::list a{ 1,2,4,4,4,7,7,9 };
    std::list b{ 2,2,3,4,4,8 };
    using Os = std::ostream_iterator<int>; // Typ des Ausgabeiterators
    Os os{std::cout, " "};                 // Streamausgabeiterator für int
    auto run = [&a,&b,&os](auto algo) {    // nutze a, b und os
        algo(a.begin(), a.end(), b.begin(), b.end(), os); // Algorithmus aufrufen
        std::cout << '\n';
    };

    // Ergebnisse der Algorithmen
    using It = decltype(a.begin());       // Typ der Eingabeiteratoren

    run(std::merge<It,It,Os>);            // Ausgabe: 1 2 2 2 3 4 4 4 4 4 7 7 8 9
    run(std::set_union<It,It,Os>);        // Ausgabe: 1 2 2 3 4 4 4 7 7 8 9
    run(std::set_intersection<It,It,Os>); // Ausgabe: 2 4 4
    run(std::set_difference<It,It,Os>);   // Ausgabe: 1 4 7 7 9
    run(std::set_symmetric_difference<It,It,Os>); // Ausgabe: 1 2 3 4 7 7 8 9

    // Mit Buchstaben wird es noch klarer
    std::string x = "abdddggi";
    std::string y = "BBCDDH";
    using Us = std::ostream_iterator<char>;   // Typ des Ausgabeiterators
    Us us{std::cout, ""};                     // Streamausgabeiterator für char
    auto compare = [](auto c, auto d) { return toupper(c) < toupper(d); };
    auto run2 = [&x,&y,&us,&compare](auto algo) {    // nutze x, y und us
        algo(x.begin(), x.end(), y.begin(), y.end(), us, compare);
        std::cout << '\n';
    };
    // Ergebnisse der Algorithmen
    using Jt = decltype(x.begin());           // Typ der Eingabeiteratoren
    using Cm = decltype(compare);             // Typ der Vergleichsfunktion

    run2(std::merge<Jt,Jt,Us,Cm>);            // Ausgabe: abBBCdddDDggHi
    run2(std::set_union<Jt,Jt,Us,Cm>);        // Ausgabe: abBCdddggHi
    run2(std::set_intersection<Jt,Jt,Us,Cm>); // Ausgabe: bdd
    run2(std::set_difference<Jt,Jt,Us,Cm>);   // Ausgabe: adggi
    run2(std::set_symmetric_difference<Jt,Jt,Us,Cm>); // Ausgabe: aBCdggHi
}

Godbolt Listing lst-0833-godb.cpp, https://godbolt.org/z/qW4hvE9s3:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qW4hvE9s3 
#include <algorithm>
#include <iostream>
#include <list>
#include <string>
#include <iterator> // ostream_iterator
#include <cctype>   // toupper
using std::toupper;
int main() {
    std::list a{ 1,2,4,4,4,7,7,9 };
    std::list b{ 2,2,3,4,4,8 };
    using Os = std::ostream_iterator<int>; // Typ des Ausgabeiterators
    Os os{std::cout, " "};                 // Streamausgabeiterator für int
    auto run = [&a,&b,&os](auto algo) {    // nutze a, b und os
        algo(a.begin(), a.end(), b.begin(), b.end(), os); // Algorithmus aufrufen
        std::cout << '\n';
    };

    // Ergebnisse der Algorithmen
    using It = decltype(a.begin());       // Typ der Eingabeiteratoren

    run(std::merge<It,It,Os>);            // Ausgabe: 1 2 2 2 3 4 4 4 4 4 7 7 8 9
    run(std::set_union<It,It,Os>);        // Ausgabe: 1 2 2 3 4 4 4 7 7 8 9
    run(std::set_intersection<It,It,Os>); // Ausgabe: 2 4 4
    run(std::set_difference<It,It,Os>);   // Ausgabe: 1 4 7 7 9
    run(std::set_symmetric_difference<It,It,Os>); // Ausgabe: 1 2 3 4 7 7 8 9

    // Mit Buchstaben wird es noch klarer
    std::string x = "abdddggi";
    std::string y = "BBCDDH";
    using Us = std::ostream_iterator<char>;   // Typ des Ausgabeiterators
    Us us{std::cout, ""};                     // Streamausgabeiterator für char
    auto compare = [](auto c, auto d) { return toupper(c) < toupper(d); };
    auto run2 = [&x,&y,&us,&compare](auto algo) {    // nutze x, y und us
        algo(x.begin(), x.end(), y.begin(), y.end(), us, compare);
        std::cout << '\n';
    };
    // Ergebnisse der Algorithmen
    using Jt = decltype(x.begin());           // Typ der Eingabeiteratoren
    using Cm = decltype(compare);             // Typ der Vergleichsfunktion

    run2(std::merge<Jt,Jt,Us,Cm>);            // Ausgabe: abBBCdddDDggHi
    run2(std::set_union<Jt,Jt,Us,Cm>);        // Ausgabe: abBCdddggHi
    run2(std::set_intersection<Jt,Jt,Us,Cm>); // Ausgabe: bdd
    run2(std::set_difference<Jt,Jt,Us,Cm>);   // Ausgabe: adggi
    run2(std::set_symmetric_difference<Jt,Jt,Us,Cm>); // Ausgabe: aBCdggHi
}

GodboltId:73hTTM7s6

Book listing lst-0834-book.cpp:

// https://godbolt.org/z/73hTTM7s6 
#include <iostream>
#include <algorithm>
#include <string>
void one(std::string &seq) {
    std::ranges::next_permutation(seq);
    std::cout << seq << '\n';
}
int main() {
    std::string seq = "BDK";
    std::cout << seq << '\n'; // Ausgabe: BDK
    auto limit = 3*2*1;       // n!
    for(int i=0; i<limit; ++i)
        one(seq);
    // Hier ist die Sequenz wieder in ihrem Ursprungszustand.
}

Godbolt Listing lst-0834-godb.cpp, https://godbolt.org/z/73hTTM7s6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/73hTTM7s6 
#include <iostream>
#include <algorithm>
#include <string>
void one(std::string &seq) {
    std::ranges::next_permutation(seq);
    std::cout << seq << '\n';
}
int main() {
    std::string seq = "BDK";
    std::cout << seq << '\n'; // Ausgabe: BDK
    auto limit = 3*2*1;       // n!
    for(int i=0; i<limit; ++i)
        one(seq);
    // Hier ist die Sequenz wieder in ihrem Ursprungszustand.
}

Listing 25.15: »accumulate«

Book listing lst-0835-book.cpp:

// https://godbolt.org/z/8sEdxd5jP 
#include <numeric>    // accumulate
#include <functional> // multiplies
#include <algorithm>  // transform, fold_left
#include <iostream>
#include <vector>
using std::accumulate; using std::cout; using std::vector; using std::multiplies;
namespace rs = std::ranges;
int main() {
  vector data{ 2, 3, 5, 10, 20 };
  cout << accumulate(data.begin(),data.end(),0)<<'\n';     // +, Ausgabe: 40
  cout << rs::fold_left(data, 1, multiplies<int>{})<<'\n'; // *, 6000
  vector<bool> gerade( data.size() );
  std::transform( data.begin(), data.end(), gerade.begin(),
      [](auto n) { return n%2==0; });
  for(auto b : gerade) {
      cout << ( b ? "gerade " : "ungerade ");
  }
  cout << "\n";       // Ausgabe: gerade ungerade ungerade gerade gerade
  auto sindAlleGerade = accumulate(gerade.begin(), gerade.end(), true,
          [](auto b, auto c) { return b&&c; });
  if(sindAlleGerade) {
      cout << "alles gerade Zahlen\n";
  } else {
      cout << "ungerade Zahlen dabei\n"; // das ist die Ausgabe
  }
}

Godbolt Listing lst-0835-godb.cpp, https://godbolt.org/z/8sEdxd5jP:

//#(compile) c++; compiler:g132; options:"-std=c++23"; libs:-
// https://godbolt.org/z/8sEdxd5jP 
#include <numeric>    // accumulate
#include <functional> // multiplies
#include <algorithm>  // transform, fold_left
#include <iostream>
#include <vector>
using std::accumulate; using std::cout; using std::vector; using std::multiplies;
namespace rs = std::ranges;
int main() {
  vector data{ 2, 3, 5, 10, 20 };
  cout << accumulate(data.begin(),data.end(),0)<<'\n';     // +, Ausgabe: 40
  cout << rs::fold_left(data, 1, multiplies<int>{})<<'\n'; // *, 6000
  vector<bool> gerade( data.size() );
  std::transform( data.begin(), data.end(), gerade.begin(),
      [](auto n) { return n%2==0; });
  for(auto b : gerade) {
      cout << ( b ? "gerade " : "ungerade ");
  }
  cout << "\n";       // Ausgabe: gerade ungerade ungerade gerade gerade
  auto sindAlleGerade = accumulate(gerade.begin(), gerade.end(), true,
          [](auto b, auto c) { return b&&c; });
  if(sindAlleGerade) {
      cout << "alles gerade Zahlen\n";
  } else {
      cout << "ungerade Zahlen dabei\n"; // das ist die Ausgabe
  }
}

Listing 25.16: »adjacent_difference« und »pairwise_transform«

Book listing lst-0836-book.cpp:

// https://godbolt.org/z/z4ajz5E5P 
#include <numeric>    // adjacent_difference
#include <functional> // plus
#include <algorithm>  // copy
#include <iostream>
#include <iterator>   // ostream_iterator
#include <vector>
#include <ranges>     // pairwise_transform
using std::cout; using std::vector; namespace vs = std::views;
int main() {
    // Streamausgabeiterator für int;
    std::ostream_iterator<int> os{std::cout, " "};
    vector data{ 1, -1, 2, -2, -4, 4, -6, 6 };
    std::copy(data.begin(), data.end (), os);
    cout << '\n'; // Ausgabe: 1 –1 2 –2 –4 4 –6 6
    vector<int> res( data.size()-1 ); // Platz für Ergebnis
    // Ergebnisse nach res schreiben:
    adjacent_difference(data.begin(), data.end(), res.begin());
    std::copy (res.begin(), res.end (), os);
    cout << '\n'; // Ausgabe: 1 –2 3 –4 –2 8 –10
    // gleich nach os schreiben:
    adjacent_difference(data.begin(), data.end(), os, std::plus<int>{});
    cout << '\n'; // Ausgabe: 1 0 1 0 –6 0 –2 0
    // oder via Range-Adapter:
    for(auto e: vs::pairwise_transform(data, std::plus<int>{}))
        cout << e << ' ';
    cout << '\n'; // Ausgabe: 0 1 0 –6 0 –2 0
}

Godbolt Listing lst-0836-godb.cpp, https://godbolt.org/z/z4ajz5E5P:

//#(compile) c++; compiler:g132; options:"-std=c++23"; libs:-
// https://godbolt.org/z/z4ajz5E5P 
#include <numeric>    // adjacent_difference
#include <functional> // plus
#include <algorithm>  // copy
#include <iostream>
#include <iterator>   // ostream_iterator
#include <vector>
#include <ranges>     // pairwise_transform
using std::cout; using std::vector; namespace vs = std::views;
int main() {
    // Streamausgabeiterator für int;
    std::ostream_iterator<int> os{std::cout, " "};
    vector data{ 1, -1, 2, -2, -4, 4, -6, 6 };
    std::copy(data.begin(), data.end (), os);
    cout << '\n'; // Ausgabe: 1 –1 2 –2 –4 4 –6 6
    vector<int> res( data.size()-1 ); // Platz für Ergebnis
    // Ergebnisse nach res schreiben:
    adjacent_difference(data.begin(), data.end(), res.begin());
    std::copy (res.begin(), res.end (), os);
    cout << '\n'; // Ausgabe: 1 –2 3 –4 –2 8 –10
    // gleich nach os schreiben:
    adjacent_difference(data.begin(), data.end(), os, std::plus<int>{});
    cout << '\n'; // Ausgabe: 1 0 1 0 –6 0 –2 0
    // oder via Range-Adapter:
    for(auto e: vs::pairwise_transform(data, std::plus<int>{}))
        cout << e << ' ';
    cout << '\n'; // Ausgabe: 0 1 0 –6 0 –2 0
}

Listing 25.17: »iota«, »stride« und »take«

Book listing lst-0837-book.cpp:

// https://godbolt.org/z/aPoe3d873 
#include <numeric>   // accumulate, iota
#include <algorithm> // copy
#include <iostream>
#include <iterator>  // ostream_iterator
#include <vector>
#include <ranges>    // iota, take, stride
using std::accumulate; using std::cout; using std::vector; 
namespace vs = std::views;
struct Generator {
    int state_;
    void operator++() { state_ += state_; }
    operator int() { return state_; }
};
int main() {
    std::ostream_iterator<int> os{std::cout, " "}; // Streamausgabeiterator für int
    vector<int> data(7);
    std::iota(data.begin(), data.end(), 10);
    std::copy(data.begin(), data.end (), os);
    cout << '\n';          // Ausgabe: 10 11 12 13 14 15 16
    vector<int> seq(7);
    std::iota(seq.begin(), seq.end(), Generator{2});
    std::copy(seq.begin(), seq.end(), os);
    cout << '\n';          // Ausgabe: 2 4 8 16 32 64 128
    for(auto i: vs::iota(0) | vs::stride(3) | vs::take(6))
        cout << i << ' ';
    cout << '\n';          // Ausgabe: 0 3 6 9 12 15
}

Godbolt Listing lst-0837-godb.cpp, https://godbolt.org/z/aPoe3d873:

//#(compile) c++; compiler:g132; options:"-std=c++23"; libs:-
// https://godbolt.org/z/aPoe3d873 
#include <numeric>   // accumulate, iota
#include <algorithm> // copy
#include <iostream>
#include <iterator>  // ostream_iterator
#include <vector>
#include <ranges>    // iota, take, stride
using std::accumulate; using std::cout; using std::vector; 
namespace vs = std::views;
struct Generator {
    int state_;
    void operator++() { state_ += state_; }
    operator int() { return state_; }
};
int main() {
    std::ostream_iterator<int> os{std::cout, " "}; // Streamausgabeiterator für int
    vector<int> data(7);
    std::iota(data.begin(), data.end(), 10);
    std::copy(data.begin(), data.end (), os);
    cout << '\n';          // Ausgabe: 10 11 12 13 14 15 16
    vector<int> seq(7);
    std::iota(seq.begin(), seq.end(), Generator{2});
    std::copy(seq.begin(), seq.end(), os);
    cout << '\n';          // Ausgabe: 2 4 8 16 32 64 128
    for(auto i: vs::iota(0) | vs::stride(3) | vs::take(6))
        cout << i << ' ';
    cout << '\n';          // Ausgabe: 0 3 6 9 12 15
}

Listing 25.18: »inclusive_scan« und »exclusive_scan«

Book listing lst-0838-book.cpp:

// https://godbolt.org/z/qcWsdedMz 
#include <numeric> // *_scan
#include <iostream>
#include <vector>
using std::inclusive_scan; using std::exclusive_scan;
std::ostream& operator<<=(std::ostream&os, const std::vector<int>&data) {
    for(auto &e : data) os << e << ' '; return os << '\n';
}
int main() {
  std::vector data{ 1, 3, 10, 18, 30, 50 };
  std::vector<int> result(6);    // 6 Elemente
  auto plus = [](auto a, auto b) { return a+b; };
  inclusive_scan(data.begin(),data.end(), result.begin(), plus, 100);
  std::cout <<= result;
  // Ausgabe: 101 104 114 132 162 212
  exclusive_scan(data.begin(),data.end(), result.begin(), 100);
  std::cout <<= result;
  // Ausgabe: 100 101 104 114 132 162
}

Godbolt Listing lst-0838-godb.cpp, https://godbolt.org/z/qcWsdedMz:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qcWsdedMz 
#include <numeric> // *_scan
#include <iostream>
#include <vector>
using std::inclusive_scan; using std::exclusive_scan;
std::ostream& operator<<=(std::ostream&os, const std::vector<int>&data) {
    for(auto &e : data) os << e << ' '; return os << '\n';
}
int main() {
  std::vector data{ 1, 3, 10, 18, 30, 50 };
  std::vector<int> result(6);    // 6 Elemente
  auto plus = [](auto a, auto b) { return a+b; };
  inclusive_scan(data.begin(),data.end(), result.begin(), plus, 100);
  std::cout <<= result;
  // Ausgabe: 101 104 114 132 162 212
  exclusive_scan(data.begin(),data.end(), result.begin(), 100);
  std::cout <<= result;
  // Ausgabe: 100 101 104 114 132 162
}

GodboltId:dKPbjj1f8

Book listing lst-0839-book.cpp:

// https://godbolt.org/z/dKPbjj1f8 
#include <iostream>
#include <memory>    // uninitialized_copy
#include <alloca.h>  // alloca (Linux)
#include <list>
int main () {
  const std::list input{1,9,2,6,6,6,8};
  const auto SZ = input.size();
  // uninitialisierter Speicherbereich:
  int* ziel = (int*)alloca(sizeof(int) * SZ); // Platz für 7 ints
  std::uninitialized_copy(input.begin(), input.end(), ziel);
  // Testausgabe
  for(int idx=0; idx<SZ; ++idx) {
    std::cout << ziel[idx] << ' ';
  }
  std::cout << '\n'; // Ausgabe: 1 9 2 6 6 6 8
}

Godbolt Listing lst-0839-godb.cpp, https://godbolt.org/z/dKPbjj1f8:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dKPbjj1f8 
#include <iostream>
#include <memory>    // uninitialized_copy
#include <alloca.h>  // alloca (Linux)
#include <list>
int main () {
  const std::list input{1,9,2,6,6,6,8};
  const auto SZ = input.size();
  // uninitialisierter Speicherbereich:
  int* ziel = (int*)alloca(sizeof(int) * SZ); // Platz für 7 ints
  std::uninitialized_copy(input.begin(), input.end(), ziel);
  // Testausgabe
  for(int idx=0; idx<SZ; ++idx) {
    std::cout << ziel[idx] << ' ';
  }
  std::cout << '\n'; // Ausgabe: 1 9 2 6 6 6 8
}

Listing 25.19: Ein eigener Algorithmus

Book listing lst-0841-book.cpp:

// https://godbolt.org/z/n8ErWj7j6 
template<typename It, typename Func>
void adjacent_pair(It begin, It end, Func func) {
    if(begin != end) {
        It prev = begin;    // erstes Argument
        ++begin;            // zweites Argument
        for(; begin != end; ++begin, ++prev) {
            func(*prev, *begin);
        }
    }
}

Godbolt Listing lst-0841-godb.cpp, https://godbolt.org/z/n8ErWj7j6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/n8ErWj7j6 
template<typename It, typename Func>
void adjacent_pair(It begin, It end, Func func) {
    if(begin != end) {
        It prev = begin;    // erstes Argument
        ++begin;            // zweites Argument
        for(; begin != end; ++begin, ++prev) {
            func(*prev, *begin);
        }
    }
}

Listing 25.20: Der Einsatz von adjacent_pair

Book listing lst-0842-book.cpp:

// https://godbolt.org/z/91jj8Toqs 
#include <vector>
#include <iostream>
// … adjacent_pair von oben hier …
int main() {
    std::vector v{1,2,3,4};
    auto f = [](auto a, auto b) { std::cout << (a+b) << ' '; };
    adjacent_pair(v.begin(), v.end(), f); // 3 5 7
    std::cout << '\n';

    std::vector x{4,8};
    adjacent_pair(x.begin(), x.end(), f); // 12
    std::cout << '\n';

    std::vector w{4};
    adjacent_pair(w.begin(), w.end(), f); // nichts
    std::cout << '\n';

    std::vector<int> y{};
    adjacent_pair(y.begin(), y.end(), f); // nichts
    std::cout << '\n';
}

Godbolt Listing lst-0842-godb.cpp, https://godbolt.org/z/91jj8Toqs:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/91jj8Toqs 
#include <vector>
#include <iostream>
// … adjacent_pair von oben hier …
int main() {
    std::vector v{1,2,3,4};
    auto f = [](auto a, auto b) { std::cout << (a+b) << ' '; };
    adjacent_pair(v.begin(), v.end(), f); // 3 5 7
    std::cout << '\n';

    std::vector x{4,8};
    adjacent_pair(x.begin(), x.end(), f); // 12
    std::cout << '\n';

    std::vector w{4};
    adjacent_pair(w.begin(), w.end(), f); // nichts
    std::cout << '\n';

    std::vector<int> y{};
    adjacent_pair(y.begin(), y.end(), f); // nichts
    std::cout << '\n';
}

Listing 25.21: Eigene Range-Adapter für Views

Book listing lst-0843-book.cpp:

// https://godbolt.org/z/dfoorEdYT 
#include <ranges>
#include <iostream>
#include <string_view>
#include <vector>
using namespace std::literals;
using namespace std; namespace vs = std::views; namespace rs = std::ranges;

// Beispiel 1
class Add_1: public rs::range_adaptor_closure<Add_1> { 
  // von Hilfsklasse ableiten
public:
  template<rs::input_range R>
  constexpr auto operator()(R&& r) const {         // universelle Referenz
    return forward<R>(r)                           // universelle Referenz erhalten
      | vs::transform([](auto i) {return i+1;});   // Ihre Implementierung
  }
};
Add_1 add_1{};                                     // Range-Adapter erzeugen

// Beispiel 2
class Dna_to_rna: public rs::range_adaptor_closure<Dna_to_rna> { // ableiten
public:
  template<rs::input_range R>
  constexpr auto operator()(R&& r) const {         // universelle Referenz
    return forward<R>(r)                           // universelle Referenz erhalten
      | vs::transform([](char c)                   // Ihre Implementierung
      {
        switch(c) {
          case 'T': return 'U';
          case 't': return 'u';
          default: return c;
        }
    });
  }
};
Dna_to_rna dna_to_rna{};                           // Range-Adapter erzeugen
// Beispiele benutzen
int main() {
  vector vec{1, 2, 3, 4, 5};
  for(auto i: vec | add_1)                         // benutzen
    cout << i << ' ';
  cout << '\n';         // Ausgabe: 2 3 4 5 6
  auto telo_rep = "TTAGGGTTAGGGTTAGGGTTAGGGT"sv;
  for(auto c: telo_rep | dna_to_rna)  // benutzen
        cout << c;
  cout << '\n';         // Ausgabe: UUAGGGUUAGGGUUAGGGUUAGGGU
}

Godbolt Listing lst-0843-godb.cpp, https://godbolt.org/z/dfoorEdYT:

//#(compile) c++; compiler:g132; options:"-std=c++23"; libs:-
// https://godbolt.org/z/dfoorEdYT 
#include <ranges>
#include <iostream>
#include <string_view>
#include <vector>
using namespace std::literals;
using namespace std; namespace vs = std::views; namespace rs = std::ranges;

// Beispiel 1
class Add_1: public rs::range_adaptor_closure<Add_1> { 
  // von Hilfsklasse ableiten
public:
  template<rs::input_range R>
  constexpr auto operator()(R&& r) const {         // universelle Referenz
    return forward<R>(r)                           // universelle Referenz erhalten
      | vs::transform([](auto i) {return i+1;});   // Ihre Implementierung
  }
};
Add_1 add_1{};                                     // Range-Adapter erzeugen

// Beispiel 2
class Dna_to_rna: public rs::range_adaptor_closure<Dna_to_rna> { // ableiten
public:
  template<rs::input_range R>
  constexpr auto operator()(R&& r) const {         // universelle Referenz
    return forward<R>(r)                           // universelle Referenz erhalten
      | vs::transform([](char c)                   // Ihre Implementierung
      {
        switch(c) {
          case 'T': return 'U';
          case 't': return 'u';
          default: return c;
        }
    });
  }
};
Dna_to_rna dna_to_rna{};                           // Range-Adapter erzeugen
// Beispiele benutzen
int main() {
  vector vec{1, 2, 3, 4, 5};
  for(auto i: vec | add_1)                         // benutzen
    cout << i << ' ';
  cout << '\n';         // Ausgabe: 2 3 4 5 6
  auto telo_rep = "TTAGGGTTAGGGTTAGGGTTAGGGT"sv;
  for(auto c: telo_rep | dna_to_rna)  // benutzen
        cout << c;
  cout << '\n';         // Ausgabe: UUAGGGUUAGGGUUAGGGUUAGGGU
}

Listing 26.1: Mit einem »vector« können Sie ein »set« simulieren.

Book listing lst-0844-book.cpp:

// https://godbolt.org/z/8d8qPWPcG 
#include <vector>
#include <iostream>
#include <algorithm>
using std::vector; using std::ostream; using std::cout;
int main() {
    vector<int> data{};
    data.reserve(400);                    // Platz für 400 Elemente
    // Phase 1: befüllen
    for(int idx = 1; idx <= 20; ++idx) {
        for(int val = 0; val < 20; ++val) {
            data.push_back(val % idx);    // irgendwas zwischen 0 und 19
        }
    }
    cout << data.size() << '\n';          // 400 Elemente zwischen 0 und 19
    // Nachbereitung Phase 1: set-Äquivalent erstellen
    std::sort(data.begin(), data.end());  // Vorbereitung für unique
    auto wo = std::unique(data.begin(), data.end()); // doppelte ans Ende
    data.erase(wo, data.end());           // doppelte wegräumen
    data.shrink_to_fit();
    cout << data.size() << '\n';          // nur noch 20 Elemente
    // Phase 2: benutzen
    for(auto &e:data)
        cout << e << ' ';                 // Ausgabe: 0 1 2 .. 18 19
    cout << '\n';
    auto it = std::lower_bound(data.begin(), data.end(), 16); // suche Wert
    if(it!=data.end() && *it == 16)
        cout << "gefunden!\n";
    if(std::binary_search(data.begin(), data.end(), 7))       // ja oder nein
        cout << "auch gefunden!\n";
}

Godbolt Listing lst-0844-godb.cpp, https://godbolt.org/z/8d8qPWPcG:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8d8qPWPcG 
#include <vector>
#include <iostream>
#include <algorithm>
using std::vector; using std::ostream; using std::cout;
int main() {
    vector<int> data{};
    data.reserve(400);                    // Platz für 400 Elemente
    // Phase 1: befüllen
    for(int idx = 1; idx <= 20; ++idx) {
        for(int val = 0; val < 20; ++val) {
            data.push_back(val % idx);    // irgendwas zwischen 0 und 19
        }
    }
    cout << data.size() << '\n';          // 400 Elemente zwischen 0 und 19
    // Nachbereitung Phase 1: set-Äquivalent erstellen
    std::sort(data.begin(), data.end());  // Vorbereitung für unique
    auto wo = std::unique(data.begin(), data.end()); // doppelte ans Ende
    data.erase(wo, data.end());           // doppelte wegräumen
    data.shrink_to_fit();
    cout << data.size() << '\n';          // nur noch 20 Elemente
    // Phase 2: benutzen
    for(auto &e:data)
        cout << e << ' ';                 // Ausgabe: 0 1 2 .. 18 19
    cout << '\n';
    auto it = std::lower_bound(data.begin(), data.end(), 16); // suche Wert
    if(it!=data.end() && *it == 16)
        cout << "gefunden!\n";
    if(std::binary_search(data.begin(), data.end(), 7))       // ja oder nein
        cout << "auch gefunden!\n";
}

GodboltId:fv3963reh

Book listing lst-0845-book.cpp:

// https://godbolt.org/z/fv3963reh 
#include <iostream>  // cout
#include <algorithm> // copy
#include <iterator>  // ostream_iterator
#include <vector>
int main() {
  std::vector<char> pfad{};
  for (char ch = 'a'; ch <= 'z'; ++ch) {
    pfad.push_back(ch);
  }
  std::ranges::copy(pfad, // hier alles, geht aber auch mit anderen Ranges
    std::ostream_iterator<char>(std::cout, " ") // kopiere nach cout, Separator " "
  );
}

Godbolt Listing lst-0845-godb.cpp, https://godbolt.org/z/fv3963reh:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fv3963reh 
#include <iostream>  // cout
#include <algorithm> // copy
#include <iterator>  // ostream_iterator
#include <vector>
int main() {
  std::vector<char> pfad{};
  for (char ch = 'a'; ch <= 'z'; ++ch) {
    pfad.push_back(ch);
  }
  std::ranges::copy(pfad, // hier alles, geht aber auch mit anderen Ranges
    std::ostream_iterator<char>(std::cout, " ") // kopiere nach cout, Separator " "
  );
}

Listing 26.2: Sie erhalten ein um ein Element vergrößertes Array zurück.

Book listing lst-0846-book.cpp:

// https://godbolt.org/z/jT7raEfKa 
#include <iostream>
#include <array>
#include <vector>
#include <string>
using std::array; using std::move; using std::forward;

// == array vergrößern ==
template<typename T, size_t S, std::size_t... Idx>
constexpr array<T, S+1>
help_append(array<T, S>&& data, T&& elem, std::index_sequence<Idx...>) {
  return { std::get<Idx>(forward<array<T, S>>(data))..., forward<T>(elem) };
}
template<typename T, size_t S>
constexpr auto
append(array<T, S> data, T elem) {
  return help_append(move(data), move(elem),
                  std::make_index_sequence<S>{});
}

// == Beispiel ==
class Picture {            // Nullerregel; verschiebbar
  std::vector<char> data_; // viele Daten
  std::string name_;
public:
  explicit Picture(const std::string& name) : data_(1000,0), name_{name}
    { /* ... hier Bild laden ... */ }
  auto name() const { return name_; }
};
int main() {
  // vorher
  array pics{Picture{"Mona"}, Picture{"Schrei"}, Picture{"Vincent"}};
  std::cout << pics[0].name() << '\n'; // Ausgabe: Mona
  // vergrößern
  Picture neu { "Uhren" };
  auto mehr = append(move(pics), move(neu));
  // nachher
  std::cout << pics[0].name() << '\n'; // Ausgabe:
  std::cout << mehr[0].name() << '\n'; // Ausgabe: Mona
  std::cout << mehr[3].name() << '\n'; // Ausgabe: Uhren
}

Godbolt Listing lst-0846-godb.cpp, https://godbolt.org/z/jT7raEfKa:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jT7raEfKa 
#include <iostream>
#include <array>
#include <vector>
#include <string>
using std::array; using std::move; using std::forward;

// == array vergrößern ==
template<typename T, size_t S, std::size_t... Idx>
constexpr array<T, S+1>
help_append(array<T, S>&& data, T&& elem, std::index_sequence<Idx...>) {
  return { std::get<Idx>(forward<array<T, S>>(data))..., forward<T>(elem) };
}
template<typename T, size_t S>
constexpr auto
append(array<T, S> data, T elem) {
  return help_append(move(data), move(elem),
                  std::make_index_sequence<S>{});
}

// == Beispiel ==
class Picture {            // Nullerregel; verschiebbar
  std::vector<char> data_; // viele Daten
  std::string name_;
public:
  explicit Picture(const std::string& name) : data_(1000,0), name_{name}
    { /* ... hier Bild laden ... */ }
  auto name() const { return name_; }
};
int main() {
  // vorher
  array pics{Picture{"Mona"}, Picture{"Schrei"}, Picture{"Vincent"}};
  std::cout << pics[0].name() << '\n'; // Ausgabe: Mona
  // vergrößern
  Picture neu { "Uhren" };
  auto mehr = append(move(pics), move(neu));
  // nachher
  std::cout << pics[0].name() << '\n'; // Ausgabe:
  std::cout << mehr[0].name() << '\n'; // Ausgabe: Mona
  std::cout << mehr[3].name() << '\n'; // Ausgabe: Uhren
}

Listing 26.3: »append« zur Laufzeit

Book listing lst-0850-book.cpp:

// https://godbolt.org/z/MMP16Mj3W 
#include <iostream>
#include <array>
#include <string>
using std::array;
template<typename T, size_t S>
auto append(const array<T, S>& data, T elem) {
    array<T, S+1> result {};
    for(auto i=0u; i < data.size(); ++i)
        result[i] = data[i];
    result[S] =elem;
    return result;
}
int main() {
    // vorher
    array pics { 3, 4, 5 };
    std::cout << pics[0] << '\n'; // Ausgabe: 3
    // vergrößern
    auto mehr = append(pics, 77);
    // nachher
    std::cout << mehr[3] << '\n'; // Ausgabe: 77
}

Godbolt Listing lst-0850-godb.cpp, https://godbolt.org/z/MMP16Mj3W:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MMP16Mj3W 
#include <iostream>
#include <array>
#include <string>
using std::array;
template<typename T, size_t S>
auto append(const array<T, S>& data, T elem) {
    array<T, S+1> result {};
    for(auto i=0u; i < data.size(); ++i)
        result[i] = data[i];
    result[S] =elem;
    return result;
}
int main() {
    // vorher
    array pics { 3, 4, 5 };
    std::cout << pics[0] << '\n'; // Ausgabe: 3
    // vergrößern
    auto mehr = append(pics, 77);
    // nachher
    std::cout << mehr[3] << '\n'; // Ausgabe: 77
}

Listing 26.4: Verschiedene Implementierungen eines Algorithmus, unterschieden anhand von Concepts

Book listing lst-0851-book.cpp:

// https://godbolt.org/z/scE81KfEa 
#include <iostream>
#include <vector>
#include <list>
#include <ranges>
namespace rs = std::ranges;

template<rs::range R>
void alg(R&& range) {
  if constexpr(rs::random_access_range<R>)
    std::cout << "wahlfrei.\n";
  else if constexpr(rs::bidirectional_range<R>)
    std::cout << "bidirektional, aber nicht wahlfrei\n";
  else static_assert(false, "nicht unterstützter Range-Typ");
}
int main() {
    std::vector<int> vec {};       // vector ist wahlfrei
    alg(vec);
    std::list<int> lst;            // list ist nur bidirektional
    alg(lst);
    std::istreambuf_iterator<char> i1{std::cin}, i2{}; // nicht einmal bidirektional
    auto fwd = rs::subrange{i1, i2};
    alg(fwd); //             (ERR)  Fehler: keine passende Implementierung
}

Godbolt Listing lst-0851-godb.cpp, https://godbolt.org/z/scE81KfEa:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/scE81KfEa 
#include <iostream>
#include <vector>
#include <list>
#include <ranges>
namespace rs = std::ranges;

template<rs::range R>
void alg(R&& range) {
  if constexpr(rs::random_access_range<R>)
    std::cout << "wahlfrei.\n";
  else if constexpr(rs::bidirectional_range<R>)
    std::cout << "bidirektional, aber nicht wahlfrei\n";
  else static_assert(false, "nicht unterstützter Range-Typ");
}
int main() {
    std::vector<int> vec {};       // vector ist wahlfrei
    alg(vec);
    std::list<int> lst;            // list ist nur bidirektional
    alg(lst);
    std::istreambuf_iterator<char> i1{std::cin}, i2{}; // nicht einmal bidirektional
    auto fwd = rs::subrange{i1, i2};
    alg(fwd); //             (ERR)  Fehler: keine passende Implementierung
}

Listing 27.1: Den Stream als Referenz zurückzugeben, ermöglicht das Aneinanderhängen.

Book listing lst-0854-book.cpp:

// https://godbolt.org/z/Th66Y9WvE 
#include <iostream> // cin, cout
int main() {
    int val1, val2;
    std::cout << "Bitte 2 int-Werte: ";
    std::cin >> val1 >> val2;
    std::cout << val1 << " : " << val2 << std::endl;
}

Godbolt Listing lst-0854-godb.cpp, https://godbolt.org/z/Th66Y9WvE:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Th66Y9WvE 
#include <iostream> // cin, cout
int main() {
    int val1, val2;
    std::cout << "Bitte 2 int-Werte: ";
    std::cin >> val1 >> val2;
    std::cout << val1 << " : " << val2 << std::endl;
}

Listing 27.2: Unformatierte Eingabe aus Streams

Book listing lst-0856-book.cpp:

// https://godbolt.org/z/rP6vMM1Gr 
#include <iostream>
using std::cout; using std::cin; using std::endl;
int main() {
    const unsigned int MAX = 10;
    char buffer[MAX] = {0};
    cout << "Eingabe getline : ";
    cin.getline(buffer, MAX);
    cout << std::cin.gcount()
        << " Zeichen wurden eingelesen\n";
    for(auto c : buffer) {
        if(c && c!='\0') cout.put(c);
    }
    cin.ignore(MAX, '\n');
    cout << "\nEingabe machen (mit . beenden) : ";
    char ch=0;
    while(cin.get(ch)) {
        if(ch == '.') break;
        cout.put(ch);
    }
    cout << "Eingabe beendet" << endl;
}

Godbolt Listing lst-0856-godb.cpp, https://godbolt.org/z/rP6vMM1Gr:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rP6vMM1Gr 
#include <iostream>
using std::cout; using std::cin; using std::endl;
int main() {
    const unsigned int MAX = 10;
    char buffer[MAX] = {0};
    cout << "Eingabe getline : ";
    cin.getline(buffer, MAX);
    cout << std::cin.gcount()
        << " Zeichen wurden eingelesen\n";
    for(auto c : buffer) {
        if(c && c!='\0') cout.put(c);
    }
    cin.ignore(MAX, '\n');
    cout << "\nEingabe machen (mit . beenden) : ";
    char ch=0;
    while(cin.get(ch)) {
        if(ch == '.') break;
        cout.put(ch);
    }
    cout << "Eingabe beendet" << endl;
}

Listing 27.3: Zustandsprüfungen bei Streams

Book listing lst-0858-book.cpp:

// https://godbolt.org/z/rq3eGP3cv 
#include <fstream>
#include <iostream>
using std::cout; using std::cin; using std::ofstream;
void checkIOstate(std::ios& stream) {
    if( stream.good() ) {
        cout << "Alles in Ordnung\n";
    } else if( stream.bad() ) {
        cout << "Fataler Fehler\n";
    } else if( stream.fail()) {
        cout << "Fehler bei der Ein-/Ausgabe\n";
        if( stream.eof()) {
            cout << "Ende des Datenstroms erreicht\n";
        }
    }
    stream.clear();
}
int main() {
    int val=0;
    cout << "Wert eingeben: ";
    cin >> val;
    checkIOstate( cin );
    std::ifstream file;
    file.open("nichtvorhanden.text");
    checkIOstate(file);
    std::fstream fstr;
    fstr.open("neueDatei.txt",
        ofstream::out | ofstream::in
        | ofstream::binary | ofstream::trunc);
    fstr << "Text in der Datei\n";
    fstr.seekp(std::ios_base::beg);
    char ch;
    while( fstr.good()) {
        fstr.get(ch);
        if(fstr.good()) cout.put(ch);
    }
    checkIOstate(fstr);
}

Godbolt Listing lst-0858-godb.cpp, https://godbolt.org/z/rq3eGP3cv:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rq3eGP3cv 
#include <fstream>
#include <iostream>
using std::cout; using std::cin; using std::ofstream;
void checkIOstate(std::ios& stream) {
    if( stream.good() ) {
        cout << "Alles in Ordnung\n";
    } else if( stream.bad() ) {
        cout << "Fataler Fehler\n";
    } else if( stream.fail()) {
        cout << "Fehler bei der Ein-/Ausgabe\n";
        if( stream.eof()) {
            cout << "Ende des Datenstroms erreicht\n";
        }
    }
    stream.clear();
}
int main() {
    int val=0;
    cout << "Wert eingeben: ";
    cin >> val;
    checkIOstate( cin );
    std::ifstream file;
    file.open("nichtvorhanden.text");
    checkIOstate(file);
    std::fstream fstr;
    fstr.open("neueDatei.txt",
        ofstream::out | ofstream::in
        | ofstream::binary | ofstream::trunc);
    fstr << "Text in der Datei\n";
    fstr.seekp(std::ios_base::beg);
    char ch;
    while( fstr.good()) {
        fstr.get(ch);
        if(fstr.good()) cout.put(ch);
    }
    checkIOstate(fstr);
}

Listing 27.4: Operator »bool« von Streams

Book listing lst-0859-book.cpp:

// https://godbolt.org/z/Mr6E3Ez48 
#include <iostream>
int main() {
    unsigned int val;
    std::cout << "Wert eingeben: ";
    std::cin >> val;
    if( std::cin ) { // operator bool()
        /* ... */                                   // Eingabe korrekt
    } else {
        std::cout << "Fehler bei std::cin\n";   // Fehler bei der Eingabe
    }
}

Godbolt Listing lst-0859-godb.cpp, https://godbolt.org/z/Mr6E3Ez48:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Mr6E3Ez48 
#include <iostream>
int main() {
    unsigned int val;
    std::cout << "Wert eingeben: ";
    std::cin >> val;
    if( std::cin ) { // operator bool()
        /* ... */                                   // Eingabe korrekt
    } else {
        std::cout << "Fehler bei std::cin\n";   // Fehler bei der Eingabe
    }
}

Listing 27.5: Einen Boolean als Text oder Zahl ausgeben

Book listing lst-0860-book.cpp:

// https://godbolt.org/z/s1csa51z9 
#include <iostream>
#include <iomanip>
using std::cin; using std::cout; using std::endl;

void f(bool b) {
     cout << b << endl;                    // Ausgabe:  true
}

int main () {
    bool b=true;
    cout << std::boolalpha << b << endl;   // Ausgabe: true
    b=false;
    cout << b << endl;                     // Ausgabe: false
    f(true);
    cout << std::noboolalpha << b << endl; // Ausgabe: 0
    b=true;
    cout << b << endl;                     // Ausgabe: 1
}

Godbolt Listing lst-0860-godb.cpp, https://godbolt.org/z/s1csa51z9:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/s1csa51z9 
#include <iostream>
#include <iomanip>
using std::cin; using std::cout; using std::endl;

void f(bool b) {
     cout << b << endl;                    // Ausgabe:  true
}

int main () {
    bool b=true;
    cout << std::boolalpha << b << endl;   // Ausgabe: true
    b=false;
    cout << b << endl;                     // Ausgabe: false
    f(true);
    cout << std::noboolalpha << b << endl; // Ausgabe: 0
    b=true;
    cout << b << endl;                     // Ausgabe: 1
}

Listing 27.6: Zahlenformate bei der Ausgabe

Book listing lst-0862-book.cpp:

// https://godbolt.org/z/bEKaYdssE 
#include <iostream>
#include <ios>
using std::cout; using std::endl;
void f() {
    int val = 100;
    cout << val << endl;               // Ausgabe: 0x64
}
int main() {
    int val = 255;
    cout << std::showbase;
    cout << std::dec << val << endl;   // Ausgabe: 255
    cout << std::hex << val << endl;   // Ausgabe: 0xff
    f();
    cout << std::oct << val << endl;   // Ausgabe: 0377
    cout << val << std::endl;          // Ausgabe: 0377
}

Godbolt Listing lst-0862-godb.cpp, https://godbolt.org/z/bEKaYdssE:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bEKaYdssE 
#include <iostream>
#include <ios>
using std::cout; using std::endl;
void f() {
    int val = 100;
    cout << val << endl;               // Ausgabe: 0x64
}
int main() {
    int val = 255;
    cout << std::showbase;
    cout << std::dec << val << endl;   // Ausgabe: 255
    cout << std::hex << val << endl;   // Ausgabe: 0xff
    f();
    cout << std::oct << val << endl;   // Ausgabe: 0377
    cout << val << std::endl;          // Ausgabe: 0377
}

Listing 27.7: Unterschiedliche Möglichkeiten zum Auffüllen bei der Ausgabe

Book listing lst-0863-book.cpp:

// https://godbolt.org/z/TMdzrjvhd 
#include <iostream>
#include <ios>        // left, right, internal
#include <iomanip>    // setw
using std::cout; using std::endl;
int main() {
    int val = -1000;
    cout << std::setw(10) << std::internal
         << val << endl;
    cout << std::setw(10) << std::left << val << endl;
    cout << std::setw(10) << std::right
         << val << endl;
}

Godbolt Listing lst-0863-godb.cpp, https://godbolt.org/z/TMdzrjvhd:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TMdzrjvhd 
#include <iostream>
#include <ios>        // left, right, internal
#include <iomanip>    // setw
using std::cout; using std::endl;
int main() {
    int val = -1000;
    cout << std::setw(10) << std::internal
         << val << endl;
    cout << std::setw(10) << std::left << val << endl;
    cout << std::setw(10) << std::right
         << val << endl;
}

Listing 27.8: Zahlenformate bei der Ausgabe

Book listing lst-0864-book.cpp:

// https://godbolt.org/z/sYK8oT33x 
#include <iostream>
#include <ios>        // left, right, internal
#include <iomanip>    // setw

using std::cout; using std::endl;
int main() {
    double dval = 3.14159;
    std::ios_base::fmtflags ff(std::ios::scientific|std::ios::uppercase);
    cout << std::setiosflags(ff);
    cout << dval << endl;                           // Ausgabe: 3.141590E+00
    cout << std::resetiosflags(ff) << dval << endl; // Ausgabe: 3.14159
    cout << std::setprecision(3) << dval << endl;   // Ausgabe: 3.14
    cout << std::setw(10);
    cout << std::setfill( '*' ) << 1246 << endl;    // Ausgabe: ******1246
}

Godbolt Listing lst-0864-godb.cpp, https://godbolt.org/z/sYK8oT33x:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/sYK8oT33x 
#include <iostream>
#include <ios>        // left, right, internal
#include <iomanip>    // setw

using std::cout; using std::endl;
int main() {
    double dval = 3.14159;
    std::ios_base::fmtflags ff(std::ios::scientific|std::ios::uppercase);
    cout << std::setiosflags(ff);
    cout << dval << endl;                           // Ausgabe: 3.141590E+00
    cout << std::resetiosflags(ff) << dval << endl; // Ausgabe: 3.14159
    cout << std::setprecision(3) << dval << endl;   // Ausgabe: 3.14
    cout << std::setw(10);
    cout << std::setfill( '*' ) << 1246 << endl;    // Ausgabe: ******1246
}

Listing 27.9: Eigene Manipulatoren

Book listing lst-0865-book.cpp:

// https://godbolt.org/z/TY9df9sb6 
#include <iostream>
#include <ios>        // left, right, internal
#include <iomanip>    // setw
using std::cout; using std::cin; using std::endl;
std::ostream& tabl(std::ostream& os) {
    os << '\t';
    return os;
}
std::istream& firstNum(std::istream& is) {
    char ch;
    is.get(ch);
    if( (ch >= '0') && (ch <= '9') ) {
        std::cin.putback(ch);
    }
    return is;
}
int main() {
    int val=0;
    cout << "Text1" << tabl << "Text2" << endl; // Ausgabe: Text1 (tab) Text2
    cout << "Eingabe machen: ";
    cin >> firstNum >> val;
    cout << val << std::endl; // Ausgabe: 12345
}

Godbolt Listing lst-0865-godb.cpp, https://godbolt.org/z/TY9df9sb6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TY9df9sb6 
#include <iostream>
#include <ios>        // left, right, internal
#include <iomanip>    // setw
using std::cout; using std::cin; using std::endl;
std::ostream& tabl(std::ostream& os) {
    os << '\t';
    return os;
}
std::istream& firstNum(std::istream& is) {
    char ch;
    is.get(ch);
    if( (ch >= '0') && (ch <= '9') ) {
        std::cin.putback(ch);
    }
    return is;
}
int main() {
    int val=0;
    cout << "Text1" << tabl << "Text2" << endl; // Ausgabe: Text1 (tab) Text2
    cout << "Eingabe machen: ";
    cin >> firstNum >> val;
    cout << val << std::endl; // Ausgabe: 12345
}

Listing 27.10: Manipulator als Lambda

Book listing lst-0867-book.cpp:

#include <iostream>
using std::cout; using std::endl;
int main() {
    auto ddash = [](auto &os) -> std::ostream& { return os << "-"; };
    cout << "Text1" << ddash << "Text2" << endl; // Ausgabe: Text1-Text2
}

Listing 27.11: Manipulator mit Parameter

Book listing lst-0868-book.cpp:

// https://godbolt.org/z/KKE6nWT49 
#include <iostream>
using std::cout; using std::endl;
class dendl { // Punkte gefolgt von Newline
    int dendl_;
public:
    dendl(int n=1)
      : dendl_{n} {}
    std::ostream& operator()(std::ostream& os) const { // Funktor
        for(int i=0; i<dendl_; ++i) os << '.';
        return os << '\n';
    }
};
std::ostream& operator<<( std::ostream& os, const dendl& elem) {
    return elem(os);
}
int main() {
    cout << "Text1" << dendl(4); // Ausgabe: Text1....
    cout << "Text2" << dendl(2); // Ausgabe: Text2..
    cout << "Text3" << dendl();  // Ausgabe: Text3.
}

Godbolt Listing lst-0868-godb.cpp, https://godbolt.org/z/KKE6nWT49:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KKE6nWT49 
#include <iostream>
using std::cout; using std::endl;
class dendl { // Punkte gefolgt von Newline
    int dendl_;
public:
    dendl(int n=1)
      : dendl_{n} {}
    std::ostream& operator()(std::ostream& os) const { // Funktor
        for(int i=0; i<dendl_; ++i) os << '.';
        return os << '\n';
    }
};
std::ostream& operator<<( std::ostream& os, const dendl& elem) {
    return elem(os);
}
int main() {
    cout << "Text1" << dendl(4); // Ausgabe: Text1....
    cout << "Text2" << dendl(2); // Ausgabe: Text2..
    cout << "Text3" << dendl();  // Ausgabe: Text3.
}

Listing 27.12: Format direkt beeinflussen

Book listing lst-0870-book.cpp:

// https://godbolt.org/z/csbPMYM19 
#include <iostream>
#include <ios> // hex, dec
using std::cout; using std::endl;
int main() {
    int val = 255;
    cout << std::showbase << std::hex << val << endl;   // Ausgabe: 0xff
    cout << std::noshowbase << std::dec << val << endl; // Ausgabe: 255
}

Godbolt Listing lst-0870-godb.cpp, https://godbolt.org/z/csbPMYM19:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/csbPMYM19 
#include <iostream>
#include <ios> // hex, dec
using std::cout; using std::endl;
int main() {
    int val = 255;
    cout << std::showbase << std::hex << val << endl;   // Ausgabe: 0xff
    cout << std::noshowbase << std::dec << val << endl; // Ausgabe: 255
}

Listing 27.13: Format mit »setf« und »unsetf« beeinflussen

Book listing lst-0871-book.cpp:

// https://godbolt.org/z/1xzzMdjdM 
#include <iostream>
using std::cout; using std::endl;
int main() {
    int val = 255;
    cout.setf(std::ios_base::hex, std::ios_base::basefield);
    cout.setf(std::ios_base::showbase);
    cout << val << std::endl; // Ausgabe: 0xff
    cout.unsetf(std::ios_base::showbase);
    cout.setf(std::ios_base::dec, std::ios_base::basefield);
    cout << val << std::endl; // Ausgabe: 255
}

Godbolt Listing lst-0871-godb.cpp, https://godbolt.org/z/1xzzMdjdM:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1xzzMdjdM 
#include <iostream>
using std::cout; using std::endl;
int main() {
    int val = 255;
    cout.setf(std::ios_base::hex, std::ios_base::basefield);
    cout.setf(std::ios_base::showbase);
    cout << val << std::endl; // Ausgabe: 0xff
    cout.unsetf(std::ios_base::showbase);
    cout.setf(std::ios_base::dec, std::ios_base::basefield);
    cout << val << std::endl; // Ausgabe: 255
}

Listing 27.14: Flags sichern und wiederherstellen

Book listing lst-0872-book.cpp:

// https://godbolt.org/z/4MY1Yznv9 
#include <iostream>
using std::cout; using std::endl;
int main() {
    int val = 255;
    std::ios::fmtflags ff = std::cout.flags();
    cout.flags(std::ios::hex | std::ios::showbase);
    cout << val << endl;  // Ausgabe: 0xff
    cout.flags(ff);
    cout << val << endl;  // Ausgabe: 255
}

Godbolt Listing lst-0872-godb.cpp, https://godbolt.org/z/4MY1Yznv9:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4MY1Yznv9 
#include <iostream>
using std::cout; using std::endl;
int main() {
    int val = 255;
    std::ios::fmtflags ff = std::cout.flags();
    cout.flags(std::ios::hex | std::ios::showbase);
    cout << val << endl;  // Ausgabe: 0xff
    cout.flags(ff);
    cout << val << endl;  // Ausgabe: 255
}

Listing 27.15: Öffnen und Anlegen von Dateien

Book listing lst-0873-book.cpp:

// https://godbolt.org/z/EfEx8fdGo 
#include <fstream>
#include <iostream>
#include <string>
int main() {
    std::string name = "textfile.txt";
    std::ifstream file01;
    file01.open(name);
    if( file01.fail() ) {
        std::cout << "Konnte " << name << " nicht oeffnen\n";
    }
    std::ofstream file02("data.dat");
    if( file02.good() ) {
        std::cout << "data.dat geoeffnet bzw. erzeugt\n";
    }
    std::fstream file03;
    file03.open("database.db");
    if( !file03 ) {
        std::cout << "Konnte database.db nicht oeffnen\n";
    }
}

Godbolt Listing lst-0873-godb.cpp, https://godbolt.org/z/EfEx8fdGo:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/EfEx8fdGo 
#include <fstream>
#include <iostream>
#include <string>
int main() {
    std::string name = "textfile.txt";
    std::ifstream file01;
    file01.open(name);
    if( file01.fail() ) {
        std::cout << "Konnte " << name << " nicht oeffnen\n";
    }
    std::ofstream file02("data.dat");
    if( file02.good() ) {
        std::cout << "data.dat geoeffnet bzw. erzeugt\n";
    }
    std::fstream file03;
    file03.open("database.db");
    if( !file03 ) {
        std::cout << "Konnte database.db nicht oeffnen\n";
    }
}

Listing 27.16: Weitere Flags beim Öffnen von Dateien

Book listing lst-0874-book.cpp:

// https://godbolt.org/z/3ocr4v745 
#include <fstream>
#include <iostream>
using std::cout;
int main() {
    std::ofstream file01("testfile.txt", std::ios::out|std::ios::app);
    if(file01.fail()) {
        cout << "Konnte testfile.txt nicht öffnen\n";
    } else {
        cout << "ok.\n";
    }
    std::fstream file02;
    file02.open("database.db", std::ios::out|std::ios::trunc);
    if( !file02 ) {
        cout << "Konnte database.db nicht öffnen\n";
    } else {
        cout << "ok.\n";
    }
}

Godbolt Listing lst-0874-godb.cpp, https://godbolt.org/z/3ocr4v745:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3ocr4v745 
#include <fstream>
#include <iostream>
using std::cout;
int main() {
    std::ofstream file01("testfile.txt", std::ios::out|std::ios::app);
    if(file01.fail()) {
        cout << "Konnte testfile.txt nicht öffnen\n";
    } else {
        cout << "ok.\n";
    }
    std::fstream file02;
    file02.open("database.db", std::ios::out|std::ios::trunc);
    if( !file02 ) {
        cout << "Konnte database.db nicht öffnen\n";
    } else {
        cout << "ok.\n";
    }
}

Listing 27.17: Explizites Schließen eines Dateistreams

Book listing lst-0875-book.cpp:

// https://godbolt.org/z/arKsG6vqc 
#include <fstream>
#include <iostream>
int main() {
    std::ofstream file01("data.db");
    if( file01.fail() ) {
        std::cout << "Konnte data.db nicht öffnen\n";
    } else {
        std::cout << "ok.\n";
    }
    file01 << "Text für die Datei\n";
    if( file01.is_open()) {
        file01.close();
    }
    file01.open("data001.db");
    // Automatisch:
    {
        std::ofstream file02("data002.db");
    } // ab hier wird file02 geschlossen
} // ab hier ist auch file01 geschlossen

Godbolt Listing lst-0875-godb.cpp, https://godbolt.org/z/arKsG6vqc:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/arKsG6vqc 
#include <fstream>
#include <iostream>
int main() {
    std::ofstream file01("data.db");
    if( file01.fail() ) {
        std::cout << "Konnte data.db nicht öffnen\n";
    } else {
        std::cout << "ok.\n";
    }
    file01 << "Text für die Datei\n";
    if( file01.is_open()) {
        file01.close();
    }
    file01.open("data001.db");
    // Automatisch:
    {
        std::ofstream file02("data002.db");
    } // ab hier wird file02 geschlossen
} // ab hier ist auch file01 geschlossen

Listing 27.18: Lesen und Schreiben mit Dateien

Book listing lst-0876-book.cpp:

// https://godbolt.org/z/KzsPfMbnq 
#include <fstream>
#include <iomanip> // setw
#include <iostream>
int main() {
    std::ofstream file("data.dat");
    if( !file ) {
        std::cout << "Konnte data.dat nicht öffnen\n";
        return 1;
    }
    file << std::setw(10) << std::setfill( '*' )
         << 1234 << std::endl;
}

Godbolt Listing lst-0876-godb.cpp, https://godbolt.org/z/KzsPfMbnq:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/KzsPfMbnq 
#include <fstream>
#include <iomanip> // setw
#include <iostream>
int main() {
    std::ofstream file("data.dat");
    if( !file ) {
        std::cout << "Konnte data.dat nicht öffnen\n";
        return 1;
    }
    file << std::setw(10) << std::setfill( '*' )
         << 1234 << std::endl;
}

Listing 27.19: Byteweises Lesen und Schreiben

Book listing lst-0877-book.cpp:

// https://godbolt.org/z/43E38b6Eq 
#include <fstream>
#include <iomanip> // setw
#include <iostream>
int main() {
    std::ifstream file("data.dat");
    if( !file ) {
        std::cout << "Fehler beim Öffnen\n";
        return 1;
    }
    char ch;
    while(file.get(ch) ) {
        std::cout.put(ch);
    }
    if( file.eof() ) {
        file.clear();
    }
    file.close();
}

Godbolt Listing lst-0877-godb.cpp, https://godbolt.org/z/43E38b6Eq:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/43E38b6Eq 
#include <fstream>
#include <iomanip> // setw
#include <iostream>
int main() {
    std::ifstream file("data.dat");
    if( !file ) {
        std::cout << "Fehler beim Öffnen\n";
        return 1;
    }
    char ch;
    while(file.get(ch) ) {
        std::cout.put(ch);
    }
    if( file.eof() ) {
        file.clear();
    }
    file.close();
}

Listing 27.20: Eine Datei byteweise kopieren

Book listing lst-0878-book.cpp:

#include <fstream>
#include <iostream>
using std::cout;
int main() {
    std::ifstream file("data.dat");
    if( !file ) { /* Fehler */ cout << "ERR\n"; return 1; }
    std::ofstream filecopy("backup.dat");
    if( !filecopy ) { /* Fehler */ cout << "ERR\n"; return 1; }
    char ch;
    while(file.get(ch) ) {
        filecopy.put(ch);
    }
}

Listing 27.21: Zeilenweises Lesen und Schreiben

Book listing lst-0879-book.cpp:

// https://godbolt.org/z/7r8r31K3e 
#include <fstream>
#include <iostream>
using std::cout;
int main() {
    std::ifstream file("44fstream07.cpp");
    if( !file ) { /* Fehler */ cout << "ERR\n"; return 1; }
    std::ofstream filecopy("backup.cpp");
    if( !filecopy ) { /* Fehler */ cout << "ERR\n"; return 1; }
    std::string puffer;
    while( getline(file, puffer) ) {
        filecopy << puffer << std::endl;
        cout << puffer << std::endl;
    }
    if( file.eof() ) {
        file.clear();
    }
}

Godbolt Listing lst-0879-godb.cpp, https://godbolt.org/z/7r8r31K3e:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7r8r31K3e 
#include <fstream>
#include <iostream>
using std::cout;
int main() {
    std::ifstream file("44fstream07.cpp");
    if( !file ) { /* Fehler */ cout << "ERR\n"; return 1; }
    std::ofstream filecopy("backup.cpp");
    if( !filecopy ) { /* Fehler */ cout << "ERR\n"; return 1; }
    std::string puffer;
    while( getline(file, puffer) ) {
        filecopy << puffer << std::endl;
        cout << puffer << std::endl;
    }
    if( file.eof() ) {
        file.clear();
    }
}

Listing 27.22: Blockweises Lesen und Schreiben mit »read« und »write«

Book listing lst-0880-book.cpp:

// https://godbolt.org/z/qP8cT5n7c 
#include <fstream>
#include <iostream>
#include <vector>
using std::cout;
int main() {
    std::ifstream file("testfile.txt", std::ios::binary);
    if( !file ) { /* Fehler */ cout <<"ERR1\n"; return 1; }
    std::ofstream filecopy("backup.dat", std::ios::binary);
    if( !filecopy ) { /* Fehler */ return 1; }
    file.seekg(0, std::ios::end);
    auto size = file.tellg();
    cout << "Dateigroesse : " << size << " Byte\n";
    file.seekg(0, std::ios::beg); // Wichtig!
    std::vector<char> puffer(size);
    file.read(puffer.data(), size);
    if( !file ) { cout << "Fehler bei read...\n"; return 1;}
    cout << "Gelesen: " << file.gcount() << " Byte\n";
    filecopy.write( puffer.data(), size );
    if( !filecopy ) { cout << "Fehler bei write...\n"; return 1;}
}

Godbolt Listing lst-0880-godb.cpp, https://godbolt.org/z/qP8cT5n7c:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qP8cT5n7c 
#include <fstream>
#include <iostream>
#include <vector>
using std::cout;
int main() {
    std::ifstream file("testfile.txt", std::ios::binary);
    if( !file ) { /* Fehler */ cout <<"ERR1\n"; return 1; }
    std::ofstream filecopy("backup.dat", std::ios::binary);
    if( !filecopy ) { /* Fehler */ return 1; }
    file.seekg(0, std::ios::end);
    auto size = file.tellg();
    cout << "Dateigroesse : " << size << " Byte\n";
    file.seekg(0, std::ios::beg); // Wichtig!
    std::vector<char> puffer(size);
    file.read(puffer.data(), size);
    if( !file ) { cout << "Fehler bei read...\n"; return 1;}
    cout << "Gelesen: " << file.gcount() << " Byte\n";
    filecopy.write( puffer.data(), size );
    if( !filecopy ) { cout << "Fehler bei write...\n"; return 1;}
}

Listing 27.23: Blockweises Lesen und Schreiben mit Hilfsklasse

Book listing lst-0881-book.cpp:

// https://godbolt.org/z/b3W48s86z 
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using std::cout; using std::string;
class DataClass {
    std::string text_;
    int data_;
public:
    DataClass(string t="", int i=0)
      : text_{t}, data_{i} {}
    std::ostream& write(std::ostream& os) const {
        os << text_ << std::ends;
        os.write(reinterpret_cast<const char*>(&data_), sizeof(data_));
        return os;
    }
    std::istream& read(std::istream& is) {
        std::getline(is, text_, '\0');
        is.read(reinterpret_cast<char*>(&data_), sizeof(data_));
        return is;
    }
    std::ostream& print(std::ostream& os) {
        return os << text_ << " : " << data_ << std::endl;
    }
};
int main() {
    std::ofstream file_w("data.dat", std::ios::binary);
    if( !file_w) { cout << "Fehler bei Öffnen\n"; return 1; }
    std::vector<DataClass> vec_dat;
    vec_dat.push_back(DataClass("Ein Text", 123));
    vec_dat.push_back(DataClass("Mehr Text", 321));
    vec_dat.emplace_back("Viel mehr Text", 333);
    for(const auto &elem : vec_dat){
        elem.write(file_w);
    }
    file_w.close();
    std::ifstream file_r("data.dat", std::ios::binary);
    if( !file_r) { cout << "Fehler bei Öffnen\n"; return 1; }
    DataClass dat_r;
    while( file_r ) {
        dat_r.read(file_r);
        if( file_r.eof()) break;
        dat_r.print(cout);
    }
}

Godbolt Listing lst-0881-godb.cpp, https://godbolt.org/z/b3W48s86z:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/b3W48s86z 
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
using std::cout; using std::string;
class DataClass {
    std::string text_;
    int data_;
public:
    DataClass(string t="", int i=0)
      : text_{t}, data_{i} {}
    std::ostream& write(std::ostream& os) const {
        os << text_ << std::ends;
        os.write(reinterpret_cast<const char*>(&data_), sizeof(data_));
        return os;
    }
    std::istream& read(std::istream& is) {
        std::getline(is, text_, '\0');
        is.read(reinterpret_cast<char*>(&data_), sizeof(data_));
        return is;
    }
    std::ostream& print(std::ostream& os) {
        return os << text_ << " : " << data_ << std::endl;
    }
};
int main() {
    std::ofstream file_w("data.dat", std::ios::binary);
    if( !file_w) { cout << "Fehler bei Öffnen\n"; return 1; }
    std::vector<DataClass> vec_dat;
    vec_dat.push_back(DataClass("Ein Text", 123));
    vec_dat.push_back(DataClass("Mehr Text", 321));
    vec_dat.emplace_back("Viel mehr Text", 333);
    for(const auto &elem : vec_dat){
        elem.write(file_w);
    }
    file_w.close();
    std::ifstream file_r("data.dat", std::ios::binary);
    if( !file_r) { cout << "Fehler bei Öffnen\n"; return 1; }
    DataClass dat_r;
    while( file_r ) {
        dat_r.read(file_r);
        if( file_r.eof()) break;
        dat_r.print(cout);
    }
}

Listing 27.24: Ausgaben zwischen Threads mit »osyncstream« synchronisieren

Book listing lst-0883-book.cpp:

// https://godbolt.org/z/dz75jr1rM 
#include <iostream>
#include <thread>
#include <syncstream>
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void runFib(long von, long schritt, long bis) {
    for (auto n=von; n<=bis; n+=schritt) {
        std::osyncstream osync{ std::cout }; // Sync auf cout, solange osync existiert
        osync << "fib("<<n<<")=" << fib(n) << '\n';
    }
}
int main() {
    std::jthread f40{ runFib, 1, 3, 40 };
    std::jthread f41{ runFib, 2, 3, 41 };
    std::jthread f42{ runFib, 3, 3, 42 };
}

Godbolt Listing lst-0883-godb.cpp, https://godbolt.org/z/dz75jr1rM:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dz75jr1rM 
#include <iostream>
#include <thread>
#include <syncstream>
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void runFib(long von, long schritt, long bis) {
    for (auto n=von; n<=bis; n+=schritt) {
        std::osyncstream osync{ std::cout }; // Sync auf cout, solange osync existiert
        osync << "fib("<<n<<")=" << fib(n) << '\n';
    }
}
int main() {
    std::jthread f40{ runFib, 1, 3, 40 };
    std::jthread f41{ runFib, 2, 3, 41 };
    std::jthread f42{ runFib, 3, 3, 42 };
}

Listing 27.25: Schreiben in einen »stringstream«

Book listing lst-0884-book.cpp:

// https://godbolt.org/z/cbGbcT178 
#include <sstream>  // ostringstream
#include <iostream>
int main() {
    std::ostringstream ostr;
    double dval = 3.1415;
    int ival = 4321;
    ostr << dval << " : " << ival;
    const std::string sval = ostr.str();
    std::cout << sval << std::endl;    // Ausgabe: 3.1415 : 4321
}

Godbolt Listing lst-0884-godb.cpp, https://godbolt.org/z/cbGbcT178:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cbGbcT178 
#include <sstream>  // ostringstream
#include <iostream>
int main() {
    std::ostringstream ostr;
    double dval = 3.1415;
    int ival = 4321;
    ostr << dval << " : " << ival;
    const std::string sval = ostr.str();
    std::cout << sval << std::endl;    // Ausgabe: 3.1415 : 4321
}

Listing 27.26: Lesen aus einem »stringstream«

Book listing lst-0885-book.cpp:

// https://godbolt.org/z/1EMox3hW5 
#include <sstream>  // istringstream
#include <iostream>
int main() {
    std::istringstream istr;
    std::string sval("3.1415 : 4321");
    std::string none;
    double dval=0.0;
    int ival=0;
    istr.str(sval);                // initialisieren
    istr >> dval >> none >> ival;  // auslesen
    if( ! istr.eof() ) {
        std::cout << "Fehler beim Konvertieren\n"; return 1;
    }
    std::cout << dval << " == " << none << " == " << ival << "\n";
    // Ausgabe: 3.1415 == : == 4321
}

Godbolt Listing lst-0885-godb.cpp, https://godbolt.org/z/1EMox3hW5:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1EMox3hW5 
#include <sstream>  // istringstream
#include <iostream>
int main() {
    std::istringstream istr;
    std::string sval("3.1415 : 4321");
    std::string none;
    double dval=0.0;
    int ival=0;
    istr.str(sval);                // initialisieren
    istr >> dval >> none >> ival;  // auslesen
    if( ! istr.eof() ) {
        std::cout << "Fehler beim Konvertieren\n"; return 1;
    }
    std::cout << dval << " == " << none << " == " << ival << "\n";
    // Ausgabe: 3.1415 == : == 4321
}

Listing 27.27: Typkonvertierung mittels »stringstream«

Book listing lst-0886-book.cpp:

// https://godbolt.org/z/vs5henTrz 
#include <sstream> // stringstream
#include <iostream>
#include <stdexcept> // invalid_argument
template <class T1, class T2>
void myConvert(const T1& in, T2& out) {
    std::stringstream ss;
    ss << in;
    ss >> out;
    if( ! ss.eof() ) {
        throw std::invalid_argument("Fehler beim Konvertieren");
    }
}
int main() {
    std::string sval;
    float fval=3.1415f;
    std::string sdval("5.321");
    double dsval=0;
    std::string gehtnicht("geht nicht");
    try {
        myConvert(fval, sval);
        std::cout << sval << std::endl;  // Ausgabe: 3.1415
        myConvert(sdval, dsval);
        std::cout << dsval << std::endl; // Ausgabe: 5.321
        myConvert(gehtnicht, dsval);     // löst "Fehler beim Konvertieren" aus
    }
    catch(const std::invalid_argument& e) {
        std::cout << e.what() << std::endl;
    }
}

Godbolt Listing lst-0886-godb.cpp, https://godbolt.org/z/vs5henTrz:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vs5henTrz 
#include <sstream> // stringstream
#include <iostream>
#include <stdexcept> // invalid_argument
template <class T1, class T2>
void myConvert(const T1& in, T2& out) {
    std::stringstream ss;
    ss << in;
    ss >> out;
    if( ! ss.eof() ) {
        throw std::invalid_argument("Fehler beim Konvertieren");
    }
}
int main() {
    std::string sval;
    float fval=3.1415f;
    std::string sdval("5.321");
    double dsval=0;
    std::string gehtnicht("geht nicht");
    try {
        myConvert(fval, sval);
        std::cout << sval << std::endl;  // Ausgabe: 3.1415
        myConvert(sdval, dsval);
        std::cout << dsval << std::endl; // Ausgabe: 5.321
        myConvert(gehtnicht, dsval);     // löst "Fehler beim Konvertieren" aus
    }
    catch(const std::invalid_argument& e) {
        std::cout << e.what() << std::endl;
    }
}

Listing 27.28: Die Funktion »to_string«

Book listing lst-0887-book.cpp:

// https://godbolt.org/z/z6sYqM48e 
#include <iostream>
#include <string>
void show(double f) {
    std::cout << "os: " << f
       << "\t to_string: " << std::to_string(f) << "\n";
}
int main() {
    show(23.43);     // Ausgabe: os: 23.43    to_string: 23.430000
    show(1e-9);      // Ausgabe: os: 1e-09    to_string: 0.000000
    show(1e40);      // Ausgabe: os: 1e+40    to_string: 100…0752.000000
    show(1e-40);     // Ausgabe: os: 1e-40    to_string: 0.000000
    show(123456789); // Ausgabe: os: 1.23457e+08  to_string: 123456789.000000
}

Godbolt Listing lst-0887-godb.cpp, https://godbolt.org/z/z6sYqM48e:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/z6sYqM48e 
#include <iostream>
#include <string>
void show(double f) {
    std::cout << "os: " << f
       << "\t to_string: " << std::to_string(f) << "\n";
}
int main() {
    show(23.43);     // Ausgabe: os: 23.43    to_string: 23.430000
    show(1e-9);      // Ausgabe: os: 1e-09    to_string: 0.000000
    show(1e40);      // Ausgabe: os: 1e+40    to_string: 100…0752.000000
    show(1e-40);     // Ausgabe: os: 1e-40    to_string: 0.000000
    show(123456789); // Ausgabe: os: 1.23457e+08  to_string: 123456789.000000
}

Listing 27.29: Daten aus dem »rdbuf« übertragen

Book listing lst-0890-book.cpp:

// https://godbolt.org/z/on6W73nz1 
#include <fstream>
#include <iostream>
#include <memory> // unique_ptr
int main() {
    std::fstream file("27Streams.tex");          // Datei zum Lesen öffnen
    auto bufptr = file.rdbuf();                  // std::streambuf*
    auto size = bufptr->pubseekoff(0, file.end); // std::streamsize
    bufptr->pubseekoff(0, file.beg);             // wieder an den Anfang
    auto buffer = std::unique_ptr<char[]>(new char[size]); // Speicher holen
    auto n = bufptr->sgetn(buffer.get(), size);  // übertrage Anzahl Zeichen
    std::cout << "Zeichen gelesen: " << n << "\n";
    std::cout.write(buffer.get(), size);         // char[] ausgeben
}

Godbolt Listing lst-0890-godb.cpp, https://godbolt.org/z/on6W73nz1:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/on6W73nz1 
#include <fstream>
#include <iostream>
#include <memory> // unique_ptr
int main() {
    std::fstream file("27Streams.tex");          // Datei zum Lesen öffnen
    auto bufptr = file.rdbuf();                  // std::streambuf*
    auto size = bufptr->pubseekoff(0, file.end); // std::streamsize
    bufptr->pubseekoff(0, file.beg);             // wieder an den Anfang
    auto buffer = std::unique_ptr<char[]>(new char[size]); // Speicher holen
    auto n = bufptr->sgetn(buffer.get(), size);  // übertrage Anzahl Zeichen
    std::cout << "Zeichen gelesen: " << n << "\n";
    std::cout.write(buffer.get(), size);         // char[] ausgeben
}

Listing 27.30: So fügen Sie Pfade zusammen.

Book listing lst-0892-book.cpp:

// https://godbolt.org/z/1YPT3asMz 
#include <filesystem>   // std::filesystem
#include <iostream>
namespace fs = std::filesystem; using std::cout; using std::endl;
int main() {
    // Pfadkomponenten
    fs::path root {"/"};
    fs::path dir {"var/www/"};
    fs::path index {"index.html"};
    // zusammenfügen
    fs::path p = root / dir / index;     // operator/
    // ausgeben
    cout << "Name: " << p << endl;       // "/var/www/index.html"
    // zerlegen
    cout << "Vater: " << p.parent_path() << endl; // "/var/www"
    cout << "Name: " << p.filename() << endl;     // "index.html"
    cout << "Endung: " << p.extension() << endl;  // ".html"
    // Information
    cout << std::boolalpha;
    cout << "Existiert? " << fs::exists(p) << endl;
    cout << "Echte Datei? " << fs::is_regular_file(p) << endl;
}

Godbolt Listing lst-0892-godb.cpp, https://godbolt.org/z/1YPT3asMz:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1YPT3asMz 
#include <filesystem>   // std::filesystem
#include <iostream>
namespace fs = std::filesystem; using std::cout; using std::endl;
int main() {
    // Pfadkomponenten
    fs::path root {"/"};
    fs::path dir {"var/www/"};
    fs::path index {"index.html"};
    // zusammenfügen
    fs::path p = root / dir / index;     // operator/
    // ausgeben
    cout << "Name: " << p << endl;       // "/var/www/index.html"
    // zerlegen
    cout << "Vater: " << p.parent_path() << endl; // "/var/www"
    cout << "Name: " << p.filename() << endl;     // "index.html"
    cout << "Endung: " << p.extension() << endl;  // ".html"
    // Information
    cout << std::boolalpha;
    cout << "Existiert? " << fs::exists(p) << endl;
    cout << "Echte Datei? " << fs::is_regular_file(p) << endl;
}

GodboltId:M8xjcnKxq

Book listing lst-0893-book.cpp:

// https://godbolt.org/z/M8xjcnKxq 
#include <format>
#include <chrono>
#include <string>
#include <string_view>
#include <iostream>
using namespace std; using namespace std::literals;
void pr(string_view s) { cout << s << endl; }
double pi = 3.14159265359;

int main() {
  pr(format("Hallo, {}!", "Leser"));             // einfacher C-String
  pr(format("Hallo, {}!", "Autor"s));            // einfacher String
  pr(format("Du bist {} Jahre alt.", 30));       // Ganzzahlen
  pr(format("Das macht {:.2f} Euro.", 19.9933)); // Fließkommazahl, 2 Stellen
  pr(format("Wissenschaftlich: {:e}", -44.876)); // ergibt "-4.487600e+01"
  pr(format("Binär von {} ist {:b}.", 42, 42));  // binär ohne Basis
  pr(format("Hex von {} ist {:#x}.", 73, 73));   // hexadezimal mit Basis
  pr(format("Mit Nullen aufgefüllt: {:03}", 7)); // ergibt "007"
  pr(format("|{0:<10}|{1:^10}|{2:>10}|", "li", "mi", "re"));
  // Ausrichtung und Index
  pr(format("{} {:.9}!", "Boa", "Constrictor")); // ohne Index, String abschneiden
  using namespace std::chrono;                   // schicke Zeitangaben:
  pr(format("{}, {}", 2023y/11/5, minutes{20})); // Ausgabe: 2023-11-05, 20min
}

Godbolt Listing lst-0893-godb.cpp, https://godbolt.org/z/M8xjcnKxq:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/M8xjcnKxq 
#include <format>
#include <chrono>
#include <string>
#include <string_view>
#include <iostream>
using namespace std; using namespace std::literals;
void pr(string_view s) { cout << s << endl; }
double pi = 3.14159265359;

int main() {
  pr(format("Hallo, {}!", "Leser"));             // einfacher C-String
  pr(format("Hallo, {}!", "Autor"s));            // einfacher String
  pr(format("Du bist {} Jahre alt.", 30));       // Ganzzahlen
  pr(format("Das macht {:.2f} Euro.", 19.9933)); // Fließkommazahl, 2 Stellen
  pr(format("Wissenschaftlich: {:e}", -44.876)); // ergibt "-4.487600e+01"
  pr(format("Binär von {} ist {:b}.", 42, 42));  // binär ohne Basis
  pr(format("Hex von {} ist {:#x}.", 73, 73));   // hexadezimal mit Basis
  pr(format("Mit Nullen aufgefüllt: {:03}", 7)); // ergibt "007"
  pr(format("|{0:<10}|{1:^10}|{2:>10}|", "li", "mi", "re"));
  // Ausrichtung und Index
  pr(format("{} {:.9}!", "Boa", "Constrictor")); // ohne Index, String abschneiden
  using namespace std::chrono;                   // schicke Zeitangaben:
  pr(format("{}, {}", 2023y/11/5, minutes{20})); // Ausgabe: 2023-11-05, 20min
}

Listing 27.31: Ein Formatierer kann parsen und formatieren delegieren.

Book listing lst-0894-book.cpp:

// https://godbolt.org/z/jYsbxqzYW 
#include <format>
#include <string>
#include <vector>
#include <iostream>
struct Elb {
  std::string name;
  int geb;
  std::string epoche;
  std::string volk;
};
template<> struct std::formatter<Elb> {
  std::formatter<std::string> sub_fmt;
  constexpr auto parse(std::format_parse_context& pctx) {
    return sub_fmt.parse(pctx); // liefert iterator auf '}'
  }
  auto format(const Elb& elb, std::format_context& fctx) const {
    std::string s = std::format("{}/{} ({} {})",
        elb.name, elb.volk, elb.geb, elb.epoche);
    return sub_fmt.format(s, fctx); // formatieren delegieren
  }
};
int main() {
  std::vector<Elb> elben{
    {"Feanor", 1169, "EZ", "Nordor"},
    {"Galadriel", 1362, "EZ", "Noldor"},
    {"Legolas", 87, "DZ", "Sindar"},
    {"Elrond", 532, "EZ", "Halbelb"},
    {"Elwe", 1050, "EZ", "Sindar"},
  };
  for (const auto& e : elben) {
    std::cout << std::format("Elb: {:>20}", e) << std::endl;
  }
}

Godbolt Listing lst-0894-godb.cpp, https://godbolt.org/z/jYsbxqzYW:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jYsbxqzYW 
#include <format>
#include <string>
#include <vector>
#include <iostream>
struct Elb {
  std::string name;
  int geb;
  std::string epoche;
  std::string volk;
};
template<> struct std::formatter<Elb> {
  std::formatter<std::string> sub_fmt;
  constexpr auto parse(std::format_parse_context& pctx) {
    return sub_fmt.parse(pctx); // liefert iterator auf '}'
  }
  auto format(const Elb& elb, std::format_context& fctx) const {
    std::string s = std::format("{}/{} ({} {})",
        elb.name, elb.volk, elb.geb, elb.epoche);
    return sub_fmt.format(s, fctx); // formatieren delegieren
  }
};
int main() {
  std::vector<Elb> elben{
    {"Feanor", 1169, "EZ", "Nordor"},
    {"Galadriel", 1362, "EZ", "Noldor"},
    {"Legolas", 87, "DZ", "Sindar"},
    {"Elrond", 532, "EZ", "Halbelb"},
    {"Elwe", 1050, "EZ", "Sindar"},
  };
  for (const auto& e : elben) {
    std::cout << std::format("Elb: {:>20}", e) << std::endl;
  }
}

Listing 27.32: Ein Formatierer kann selbst parsen und ausgeben.

Book listing lst-0895-book.cpp:

// https://godbolt.org/z/WqjK31Gn6 
// 'Elb' wie zuvor…
template<> struct std::formatter<Elb> {
  std::string attribs;                 // Folge von '%n', '%g', '%e', '%v' und anderem
  constexpr auto parse(std::format_parse_context& pctx) {
    auto it = std::ranges::find(pctx.begin(), pctx.end(), '}');// suche '}'
    attribs = std::string(pctx.begin(), it);                   // alles speichern
    return it;                                                 // zeigt auf '}'
  }
  auto format(const Elb& elb, std::format_context& fctx) const {
    auto out = fctx.out();                                      // hier hinein
    for(auto n=0u; n<attribs.size()-1; ++n) {
      if(attribs[n] == '%') {             // Instruktion, ein Mitglied auszugeben
        switch(attribs[++n]) {
          case 'n': out = std::format_to(out, "{}", elb.name); break;
          case 'g': out = std::format_to(out, "{}", elb.geb); break;
          case 'e': out = std::format_to(out, "{}", elb.epoche); break;
          case 'v': out = std::format_to(out, "{}", elb.volk); break;
          case '%': out = std::format_to(out, "%"); break;      // %% wird zu %
        }
      } else {
        out = std::format_to(out, "{}", attribs[n]);           // alles andere
      }
    }
    return out;                                                // zeigt ans Ende
  }
};
int main() {
  Elb e{"Feanor", 1169, "EZ", "Nordor"};
  std::cout << std::format("{:Elb %n}", e) << std::endl;
  // Ausgabe: Elb Feanor
  std::cout << std::format("Elb {:%n, %v, geboren %g im Zeitalter %e}\n", e);
  // Ausgabe: Elb Feanor, Nordor, geboren 1169 im Zeitalter EZ
}

Godbolt Listing lst-0895-godb.cpp, https://godbolt.org/z/WqjK31Gn6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/WqjK31Gn6 
// 'Elb' wie zuvor…
template<> struct std::formatter<Elb> {
  std::string attribs;                 // Folge von '%n', '%g', '%e', '%v' und anderem
  constexpr auto parse(std::format_parse_context& pctx) {
    auto it = std::ranges::find(pctx.begin(), pctx.end(), '}');// suche '}'
    attribs = std::string(pctx.begin(), it);                   // alles speichern
    return it;                                                 // zeigt auf '}'
  }
  auto format(const Elb& elb, std::format_context& fctx) const {
    auto out = fctx.out();                                      // hier hinein
    for(auto n=0u; n<attribs.size()-1; ++n) {
      if(attribs[n] == '%') {             // Instruktion, ein Mitglied auszugeben
        switch(attribs[++n]) {
          case 'n': out = std::format_to(out, "{}", elb.name); break;
          case 'g': out = std::format_to(out, "{}", elb.geb); break;
          case 'e': out = std::format_to(out, "{}", elb.epoche); break;
          case 'v': out = std::format_to(out, "{}", elb.volk); break;
          case '%': out = std::format_to(out, "%"); break;      // %% wird zu %
        }
      } else {
        out = std::format_to(out, "{}", attribs[n]);           // alles andere
      }
    }
    return out;                                                // zeigt ans Ende
  }
};
int main() {
  Elb e{"Feanor", 1169, "EZ", "Nordor"};
  std::cout << std::format("{:Elb %n}", e) << std::endl;
  // Ausgabe: Elb Feanor
  std::cout << std::format("Elb {:%n, %v, geboren %g im Zeitalter %e}\n", e);
  // Ausgabe: Elb Feanor, Nordor, geboren 1169 im Zeitalter EZ
}

Listing 28.1: So geben Sie mit »pair« zwei Werte gleichzeitig zurück.

Book listing lst-0896-book.cpp:

// https://godbolt.org/z/4YM9d99xG 
#include <iostream>
#include <string>
#include <vector>
#include <utility> // pair
using std::pair; using std::cout; using std::cin; using std::string;
std::vector<string> monate { "Jan", "Feb", "Mar" };
std::vector temps { 8, 12, 11 };
std::pair<string, int> monatMitTemp(size_t m) {
    auto monat = monate.at(m);
    auto temperatur = temps.at(m);
    return std::make_pair(monat, temperatur);
}
int main() {
    std::pair daten = monatMitTemp(1);
    cout << "Monat : " << daten.first << std::endl; // Ausgabe: Monat : Feb
    cout << "Temperatur : " << daten.second << std::endl; 
    // Ausgabe: Temperatur : 12
}

Godbolt Listing lst-0896-godb.cpp, https://godbolt.org/z/4YM9d99xG:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4YM9d99xG 
#include <iostream>
#include <string>
#include <vector>
#include <utility> // pair
using std::pair; using std::cout; using std::cin; using std::string;
std::vector<string> monate { "Jan", "Feb", "Mar" };
std::vector temps { 8, 12, 11 };
std::pair<string, int> monatMitTemp(size_t m) {
    auto monat = monate.at(m);
    auto temperatur = temps.at(m);
    return std::make_pair(monat, temperatur);
}
int main() {
    std::pair daten = monatMitTemp(1);
    cout << "Monat : " << daten.first << std::endl; // Ausgabe: Monat : Feb
    cout << "Temperatur : " << daten.second << std::endl; 
    // Ausgabe: Temperatur : 12
}

Listing 28.2: Mit »tuple« können Sie beliebig viele Elemente zurückgeben.

Book listing lst-0897-book.cpp:

// https://godbolt.org/z/47jb7nEG4 
#include <iostream>
#include <string>
#include <algorithm> // min, max
#include <tuple>
using std::tuple; using std::make_tuple; using std::get; using std::cout;
using std::string;
tuple<int,int,int> ordne(int a, int b, int c) {
  using std::min; using std::max;
  auto x = min(a,min(b,c));
  auto y = max(min(a,b), min(max(a,b),c));
  auto z = max(a,max(b,c));
  return make_tuple(x, y, z);
}
auto praeser(int jahr) {
  using namespace std::literals;
  if(jahr>=2017)
    return make_tuple("Frank-Walter"s, "Steinmeier"s, "SPD"s, 1956);
  if(jahr>=2012)
    return make_tuple("Joachim"s, "Gauck"s, "-"s, 1940);
  // …
}
int main() {
  tuple<int,int,int> zs = ordne(23, 42, 7);
  cout << get<0>(zs) <<' '<< get<1>(zs) <<' '<< get<2>(zs) <<'\n'; 
  // Ausgabe: 7 23 42
  auto ps = praeser(2015);
  cout << get<1>(ps) << '\n'; // Ausgabe: Gauck
}

Godbolt Listing lst-0897-godb.cpp, https://godbolt.org/z/47jb7nEG4:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/47jb7nEG4 
#include <iostream>
#include <string>
#include <algorithm> // min, max
#include <tuple>
using std::tuple; using std::make_tuple; using std::get; using std::cout;
using std::string;
tuple<int,int,int> ordne(int a, int b, int c) {
  using std::min; using std::max;
  auto x = min(a,min(b,c));
  auto y = max(min(a,b), min(max(a,b),c));
  auto z = max(a,max(b,c));
  return make_tuple(x, y, z);
}
auto praeser(int jahr) {
  using namespace std::literals;
  if(jahr>=2017)
    return make_tuple("Frank-Walter"s, "Steinmeier"s, "SPD"s, 1956);
  if(jahr>=2012)
    return make_tuple("Joachim"s, "Gauck"s, "-"s, 1940);
  // …
}
int main() {
  tuple<int,int,int> zs = ordne(23, 42, 7);
  cout << get<0>(zs) <<' '<< get<1>(zs) <<' '<< get<2>(zs) <<'\n'; 
  // Ausgabe: 7 23 42
  auto ps = praeser(2015);
  cout << get<1>(ps) << '\n'; // Ausgabe: Gauck
}

Listing 28.3: »get« funktioniert mit einem Typ als Index.

Book listing lst-0898-book.cpp:

// https://godbolt.org/z/cx8b9seaW 
// … wie zuvor …
int main() {
  tuple ps = praeser(2015);
  cout << get<int>(ps) << '\n';    // Ausgabe: 1940
  cout << get<string>(ps) << '\n'; //                 (ERR)  nicht eindeutig
}

Godbolt Listing lst-0898-godb.cpp, https://godbolt.org/z/cx8b9seaW:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cx8b9seaW 
// … wie zuvor …
int main() {
  tuple ps = praeser(2015);
  cout << get<int>(ps) << '\n';    // Ausgabe: 1940
  cout << get<string>(ps) << '\n'; //                 (ERR)  nicht eindeutig
}

Listing 28.4: Tupel zerlegen mit »tie« und »ignore«

Book listing lst-0899-book.cpp:

// https://godbolt.org/z/YzTvoE3x6 
// … wie zuvor …
int main() {
  using std::tie; using std::ignore;
  string nachname {};
  int gebj {};
  tie(ignore, nachname, ignore, gebj) = praeser(2015);
  cout << nachname << ' ' << gebj << '\n'; // Ausgabe: Gauck 1940
}

Godbolt Listing lst-0899-godb.cpp, https://godbolt.org/z/YzTvoE3x6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YzTvoE3x6 
// … wie zuvor …
int main() {
  using std::tie; using std::ignore;
  string nachname {};
  int gebj {};
  tie(ignore, nachname, ignore, gebj) = praeser(2015);
  cout << nachname << ' ' << gebj << '\n'; // Ausgabe: Gauck 1940
}

Listing 28.5: Tupel implementieren lexikografische Ordnung.

Book listing lst-0900-book.cpp:

// https://godbolt.org/z/jrP4v76aj 
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
#include <algorithm> // ranges::sort
using std::tuple; using std::get; using std::cout; using std::string;
int main() {
    std::vector<tuple<string,string,int>> armstrongs =
      { {"Armstrong", "Louis", 1901}  // Initialisieren per Initialisierungsliste
      , {"Armstrong", "Lance", 1971}
      , {"Armstrong", "Neil", 1930} };
    std::ranges::sort(armstrongs);  // Lance < Louis < Neil
    for(const auto& a : armstrongs) {
      cout << get<0>(a) << ", " << get<1>(a) << ", " << get<2>(a) << "\n";
    }
}

Godbolt Listing lst-0900-godb.cpp, https://godbolt.org/z/jrP4v76aj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/jrP4v76aj 
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
#include <algorithm> // ranges::sort
using std::tuple; using std::get; using std::cout; using std::string;
int main() {
    std::vector<tuple<string,string,int>> armstrongs =
      { {"Armstrong", "Louis", 1901}  // Initialisieren per Initialisierungsliste
      , {"Armstrong", "Lance", 1971}
      , {"Armstrong", "Neil", 1930} };
    std::ranges::sort(armstrongs);  // Lance < Louis < Neil
    for(const auto& a : armstrongs) {
      cout << get<0>(a) << ", " << get<1>(a) << ", " << get<2>(a) << "\n";
    }
}

Listing 28.6: Tupel als Schlüssel

Book listing lst-0901-book.cpp:

// https://godbolt.org/z/9qhMo6zbb 
#include <iostream>
#include <string>
#include <tuple>
#include <map>
#include <unordered_set>

using std::tuple; using std::get; using std::cout; using std::string;

int main() {
    std::map<tuple<int,string>,double> m { {{12,"x"},3.14} };
    cout << m[{12,"x"}] << "\n"; // Ausgabe: 3.14
    std::unordered_set<tuple<int,string>> s { {12,"x"} }; //                 (ERR)  kein std::hash
}

Godbolt Listing lst-0901-godb.cpp, https://godbolt.org/z/9qhMo6zbb:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9qhMo6zbb 
#include <iostream>
#include <string>
#include <tuple>
#include <map>
#include <unordered_set>

using std::tuple; using std::get; using std::cout; using std::string;

int main() {
    std::map<tuple<int,string>,double> m { {{12,"x"},3.14} };
    cout << m[{12,"x"}] << "\n"; // Ausgabe: 3.14
    std::unordered_set<tuple<int,string>> s { {12,"x"} }; //                 (ERR)  kein std::hash
}

Listing 28.7: Tupel als Schlüssel

Book listing lst-0902-book.cpp:

// https://godbolt.org/z/vdT7TTjWK 
#include <iostream>
#include <string>
#include <tuple>
#include <map>
#include <unordered_set>
using std::tuple; using std::tie; using std::cout; using std::string;
struct Point {
    int x,y,z;
    bool operator<(const Point &b) {
        return tie(x,y,z) < tie(b.x, b.y, b.z);
    }
};
int main() {
    Point a{ 11, 22, 33 };
    Point b{ 11, 33, 0 };
    cout << std::boolalpha << (a < b) << "\n"; // Ausgabe: true
}

Godbolt Listing lst-0902-godb.cpp, https://godbolt.org/z/vdT7TTjWK:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vdT7TTjWK 
#include <iostream>
#include <string>
#include <tuple>
#include <map>
#include <unordered_set>
using std::tuple; using std::tie; using std::cout; using std::string;
struct Point {
    int x,y,z;
    bool operator<(const Point &b) {
        return tie(x,y,z) < tie(b.x, b.y, b.z);
    }
};
int main() {
    Point a{ 11, 22, 33 };
    Point b{ 11, 33, 0 };
    cout << std::boolalpha << (a < b) << "\n"; // Ausgabe: true
}

Listing 28.8: Mehrere kleine Tupel zu einem großen zusammenfügen

Book listing lst-0903-book.cpp:

// https://godbolt.org/z/eq1dqWbe9 
#include <iostream>
#include <string>
#include <tuple>
using std::tuple; using std::cout; using std::string;
int main() {
    tuple<int,string> a { 12, "gnorf" };
    tuple b { 666 };
    tuple<double,double,string> c { 77.77, 33.33, "frong" };
    tuple<int,string,int,double,double,string> r = std::tuple_cat( a, b, c );
    cout << std::get<2>(r) << "\n"; // Ausgabe: 666
}

Godbolt Listing lst-0903-godb.cpp, https://godbolt.org/z/eq1dqWbe9:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/eq1dqWbe9 
#include <iostream>
#include <string>
#include <tuple>
using std::tuple; using std::cout; using std::string;
int main() {
    tuple<int,string> a { 12, "gnorf" };
    tuple b { 666 };
    tuple<double,double,string> c { 77.77, 33.33, "frong" };
    tuple<int,string,int,double,double,string> r = std::tuple_cat( a, b, c );
    cout << std::get<2>(r) << "\n"; // Ausgabe: 666
}

Listing 28.9: Nützliche Tuple-Type-Traits

Book listing lst-0904-book.cpp:

// https://godbolt.org/z/Psdz9s9Gc 
#include <iostream>
#include <string>
#include <tuple>
using namespace std;
template<typename Tuple>
auto back(Tuple &&tuple) {
    using Noref = typename remove_reference<Tuple>::type; // falls Tuple&
    constexpr auto sz = tuple_size<Noref>::value;
    return get<sz-1>(forward<Tuple>(tuple));
}
int main() {
    tuple<string,int,string> enterprise = make_tuple("NCC", 1701, "D");
    cout << back(enterprise) << "\n"; // Ausgabe: D
}

Godbolt Listing lst-0904-godb.cpp, https://godbolt.org/z/Psdz9s9Gc:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Psdz9s9Gc 
#include <iostream>
#include <string>
#include <tuple>
using namespace std;
template<typename Tuple>
auto back(Tuple &&tuple) {
    using Noref = typename remove_reference<Tuple>::type; // falls Tuple&
    constexpr auto sz = tuple_size<Noref>::value;
    return get<sz-1>(forward<Tuple>(tuple));
}
int main() {
    tuple<string,int,string> enterprise = make_tuple("NCC", 1701, "D");
    cout << back(enterprise) << "\n"; // Ausgabe: D
}

Listing 28.10: Übereinstimmung, Suche und Aufzählung mit regulären Ausdrücken

Book listing lst-0905-book.cpp:

// https://godbolt.org/z/zjboebEhc 
#include <string>
#include <iostream>
#include <regex>
using std::regex; using std::sregex_iterator; using std::string;
const regex rgxMobile(R"(01[567]\d{6,10})");        // Handy 0151-0179
bool isMobilephone(const string& text) {
  return std::regex_match(text, rgxMobile);         // Passt text ganz?
}
bool containsMobilephone(const string &text) {
  return std::regex_search(text, rgxMobile);        // irgendwo in text?
}
void listMobilephones(const string &text) {
  sregex_iterator begin{ text.cbegin(), text.cend(), rgxMobile };
  sregex_iterator end;
  for(auto it = begin; it != end; ++it)
    std::cout << it->str() << " ";                  // Treffertext
} // "xyz01709999 abc 0161887766 uvw" -> "01709999 161887766"

Godbolt Listing lst-0905-godb.cpp, https://godbolt.org/z/zjboebEhc:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zjboebEhc 
#include <string>
#include <iostream>
#include <regex>
using std::regex; using std::sregex_iterator; using std::string;
const regex rgxMobile(R"(01[567]\d{6,10})");        // Handy 0151-0179
bool isMobilephone(const string& text) {
  return std::regex_match(text, rgxMobile);         // Passt text ganz?
}
bool containsMobilephone(const string &text) {
  return std::regex_search(text, rgxMobile);        // irgendwo in text?
}
void listMobilephones(const string &text) {
  sregex_iterator begin{ text.cbegin(), text.cend(), rgxMobile };
  sregex_iterator end;
  for(auto it = begin; it != end; ++it)
    std::cout << it->str() << " ";                  // Treffertext
} // "xyz01709999 abc 0161887766 uvw" -> "01709999 161887766"

Listing 28.11: Suche und Übereinstimmung

Book listing lst-0906-book.cpp:

// https://godbolt.org/z/E9hcWGMW4 
#include <regex>
#include <string>
#include <iostream>
using std::regex; using std::regex_match; using std::regex_search;
int main() {
    std::cout << std::boolalpha;
    regex muster {"ello"};
    std::string text = "Hello world";
    auto b1 = regex_match (text.cbegin(), text.cend(), muster); // passt nicht
    std::cout << b1 << "\n"; // Ausgabe: false
    auto b2 = regex_search(text.cbegin(), text.cend(), muster); // gefunden
    std::cout << b2 << "\n"; // Ausgabe: true
}

Godbolt Listing lst-0906-godb.cpp, https://godbolt.org/z/E9hcWGMW4:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/E9hcWGMW4 
#include <regex>
#include <string>
#include <iostream>
using std::regex; using std::regex_match; using std::regex_search;
int main() {
    std::cout << std::boolalpha;
    regex muster {"ello"};
    std::string text = "Hello world";
    auto b1 = regex_match (text.cbegin(), text.cend(), muster); // passt nicht
    std::cout << b1 << "\n"; // Ausgabe: false
    auto b2 = regex_search(text.cbegin(), text.cend(), muster); // gefunden
    std::cout << b2 << "\n"; // Ausgabe: true
}

Listing 28.12: Zugriff auf die Trefferdetails

Book listing lst-0907-book.cpp:

// https://godbolt.org/z/Ed8ca4Keq 
#include <regex>
#include <string>
#include <iostream>
using std::regex; using std::regex_search; using std::cmatch;
int main() {
    cmatch res;                              // für Detailergebnisse
    std::string text = "<h2>Ergebnis und Teile davon</h2>";
    regex muster{"<h(.)>([^<]+)"};           // Suchmuster mit Gruppen
    regex_search(text.c_str(), res, muster); // Details nach res
    std::cout << res[1] << ". "              // ()-Gruppe 1: H-Ebene
         << res[2] << std::endl;             // ()-Gruppe 2: H-Text
}

Godbolt Listing lst-0907-godb.cpp, https://godbolt.org/z/Ed8ca4Keq:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Ed8ca4Keq 
#include <regex>
#include <string>
#include <iostream>
using std::regex; using std::regex_search; using std::cmatch;
int main() {
    cmatch res;                              // für Detailergebnisse
    std::string text = "<h2>Ergebnis und Teile davon</h2>";
    regex muster{"<h(.)>([^<]+)"};           // Suchmuster mit Gruppen
    regex_search(text.c_str(), res, muster); // Details nach res
    std::cout << res[1] << ". "              // ()-Gruppe 1: H-Ebene
         << res[2] << std::endl;             // ()-Gruppe 2: H-Text
}

Listing 28.13: Treffer durch neuen Text ersetzen

Book listing lst-0908-book.cpp:

// https://godbolt.org/z/rErP43G89 
#include <regex>
#include <string>
#include <iostream>
using std::string;
int main() {
    string text = "Titel;Album;Interpret";
    std::regex muster{";"};
    string neu = std::regex_replace(text, muster, string{","});
    std::cout << neu << "\n"; // Ausgabe: Titel,Album,Interpret
}

Godbolt Listing lst-0908-godb.cpp, https://godbolt.org/z/rErP43G89:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rErP43G89 
#include <regex>
#include <string>
#include <iostream>
using std::string;
int main() {
    string text = "Titel;Album;Interpret";
    std::regex muster{";"};
    string neu = std::regex_replace(text, muster, string{","});
    std::cout << neu << "\n"; // Ausgabe: Titel,Album,Interpret
}

Listing 28.14: Schwer zu wartender regulärer Ausdruck

Book listing lst-0911-book.cpp:

// https://godbolt.org/z/v91WoqjPj 
#include <regex>
#include <string>
#include <iostream>
using std::regex; using std::regex_search; using std::cmatch;
const regex muster{R"(^score\s+(\d+)\s+for\s+(\d+)\s+nights?\s+at\s+(.*))"};
void extract(const std::string &text) {
    cmatch res;
    regex_search(text.c_str(), res, muster);
    std::cout << res[1] << "," << res[2] << "," << res[3] << "\n";
}
int main() {
    extract("score 400 for 2 nights at Minas Tirith Airport");
    extract("score 84 for 1 night at Prancing Pony");
}

Godbolt Listing lst-0911-godb.cpp, https://godbolt.org/z/v91WoqjPj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/v91WoqjPj 
#include <regex>
#include <string>
#include <iostream>
using std::regex; using std::regex_search; using std::cmatch;
const regex muster{R"(^score\s+(\d+)\s+for\s+(\d+)\s+nights?\s+at\s+(.*))"};
void extract(const std::string &text) {
    cmatch res;
    regex_search(text.c_str(), res, muster);
    std::cout << res[1] << "," << res[2] << "," << res[3] << "\n";
}
int main() {
    extract("score 400 for 2 nights at Minas Tirith Airport");
    extract("score 84 for 1 night at Prancing Pony");
}

Listing 28.15: Teile benennen und dann zusammenfügen

Book listing lst-0912-book.cpp:

// https://godbolt.org/z/TK6n4dG37 
const string scoreKeyword = R"(^score\s+)";
const string numberOfPoints = R"((\d+))";
const string forKeyword = R"(\s+for\s+)";
const string numberOfNights = R"((\d+))";
const string nightsAtKeyword = R"(\s+nights?\s+at\s+)";
const string hotelName = R"((.*))";
const regex muster{ scoreKeyword + numberOfPoints +
    forKeyword + numberOfNights + nightsAtKeyword + hotelName };
}

Godbolt Listing lst-0912-godb.cpp, https://godbolt.org/z/TK6n4dG37:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TK6n4dG37 
const string scoreKeyword = R"(^score\s+)";
const string numberOfPoints = R"((\d+))";
const string forKeyword = R"(\s+for\s+)";
const string numberOfNights = R"((\d+))";
const string nightsAtKeyword = R"(\s+nights?\s+at\s+)";
const string hotelName = R"((.*))";
const regex muster{ scoreKeyword + numberOfPoints +
    forKeyword + numberOfNights + nightsAtKeyword + hotelName };
}

Listing 28.16: Innerhalb des Ausdrucks kommentieren

Book listing lst-0913-book.cpp:

// https://godbolt.org/z/MszTjE3dv 
const regex muster{R"(^score)"
    R"(\s+)"
    R"((\d+))"          // Punkte
    R"(\s+)"
    R"(for)"
    R"(\s+)"
    R"((\d+))"          // Anzahl Nächte
    R"(\s+)"
    R"(night)"
    R"(s?)"             // optional: Plural
    R"(\s+)"
    R"(at)"
    R"(\s+)"
    R"((.*))"           // Hotelname
    R"()"};

Godbolt Listing lst-0913-godb.cpp, https://godbolt.org/z/MszTjE3dv:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/MszTjE3dv 
const regex muster{R"(^score)"
    R"(\s+)"
    R"((\d+))"          // Punkte
    R"(\s+)"
    R"(for)"
    R"(\s+)"
    R"((\d+))"          // Anzahl Nächte
    R"(\s+)"
    R"(night)"
    R"(s?)"             // optional: Plural
    R"(\s+)"
    R"(at)"
    R"(\s+)"
    R"((.*))"           // Hotelname
    R"()"};

Listing 28.17: So erhalten Sie eine gleichverteilte Zufallszahl zwischen zwei Grenzen.

Book listing lst-0914-book.cpp:

// https://godbolt.org/z/6ecxTsYzj 
#include <random>
#include <vector>
#include <iostream>
void wuerfel() {
  std::default_random_engine engine{};         // Zufall normaler Qualität
  std::vector<size_t> counts{0,0,0,0,0,0};
  std::uniform_int_distribution<int> w6{0, 5}; // gleichverteilte Ganzzahlen
  for(auto i=1200*1000; i>0; --i)
    ++counts[w6(engine)];
  for(auto c : counts) std::cout<<" "<<c;
  std::cout << '\n';
}
int main() {
    wuerfel();
}

Godbolt Listing lst-0914-godb.cpp, https://godbolt.org/z/6ecxTsYzj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6ecxTsYzj 
#include <random>
#include <vector>
#include <iostream>
void wuerfel() {
  std::default_random_engine engine{};         // Zufall normaler Qualität
  std::vector<size_t> counts{0,0,0,0,0,0};
  std::uniform_int_distribution<int> w6{0, 5}; // gleichverteilte Ganzzahlen
  for(auto i=1200*1000; i>0; --i)
    ++counts[w6(engine)];
  for(auto c : counts) std::cout<<" "<<c;
  std::cout << '\n';
}
int main() {
    wuerfel();
}

Listing 28.18: Geschwindigkeiten der Zufallsgeneratoren

Book listing lst-0918-book.cpp:

// https://godbolt.org/z/W8WbbxY78 
#include <random>
#include <chrono>  // system_clock
#include <format>
#include <iostream>

using namespace std;
using namespace chrono;
const size_t LOOPS = 10*1000*1000;

template<typename ENGINE>
void messen(const string &title, ENGINE &engine) {
  const auto start = steady_clock::now();

  /* hart arbeiten */
  unsigned long long checksum = 0;
  size_t loops = LOOPS;
  while(loops-- > 0)
    checksum += engine();

  const auto now = steady_clock::now();
  nanoseconds dur_ns = now - start;
  cout << std::format("  {}: {:5} ns/loop  {:12} ns\n",
      title, dur_ns.count() / LOOPS, dur_ns.count());
}

int main() {
  { default_random_engine e{}; messen("      default", e ); }
  { random_device e{};         messen("       device", e ); }
  { minstd_rand0 e{};          messen(" minstd_rand0", e ); }
  { minstd_rand e{};           messen(" minstd_rand ", e ); }
  { mt19937 e{};               messen("   mt19937   ", e ); }
  { mt19937_64 e{};            messen("   mt19937_64", e ); }
  { ranlux24_base e{};         messen("ranlux24_base", e ); }
  { ranlux48_base e{};         messen("ranlux48_base", e ); }
  { ranlux24 e{};              messen("ranlux24     ", e ); }
  { ranlux48 e{};              messen("ranlux48     ", e ); }
  { knuth_b e{};               messen("      knuth_b", e ); }
  {
    using wide_t = unsigned long long ;
    independent_bits_engine<ranlux48, sizeof(wide_t)*8, wide_t> e{};
    messen("indep<ranlux>", e );
  }
  {
    using wide_t = unsigned long long;
    independent_bits_engine<
          default_random_engine,
          sizeof(wide_t)*8, wide_t>
      e {};
    messen("indep<default>", e );
  }
}

Godbolt Listing lst-0918-godb.cpp, https://godbolt.org/z/W8WbbxY78:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/W8WbbxY78 
#include <random>
#include <chrono>  // system_clock
#include <format>
#include <iostream>

using namespace std;
using namespace chrono;
const size_t LOOPS = 10*1000*1000;

template<typename ENGINE>
void messen(const string &title, ENGINE &engine) {
  const auto start = steady_clock::now();

  /* hart arbeiten */
  unsigned long long checksum = 0;
  size_t loops = LOOPS;
  while(loops-- > 0)
    checksum += engine();

  const auto now = steady_clock::now();
  nanoseconds dur_ns = now - start;
  cout << std::format("  {}: {:5} ns/loop  {:12} ns\n",
      title, dur_ns.count() / LOOPS, dur_ns.count());
}

int main() {
  { default_random_engine e{}; messen("      default", e ); }
  { random_device e{};         messen("       device", e ); }
  { minstd_rand0 e{};          messen(" minstd_rand0", e ); }
  { minstd_rand e{};           messen(" minstd_rand ", e ); }
  { mt19937 e{};               messen("   mt19937   ", e ); }
  { mt19937_64 e{};            messen("   mt19937_64", e ); }
  { ranlux24_base e{};         messen("ranlux24_base", e ); }
  { ranlux48_base e{};         messen("ranlux48_base", e ); }
  { ranlux24 e{};              messen("ranlux24     ", e ); }
  { ranlux48 e{};              messen("ranlux48     ", e ); }
  { knuth_b e{};               messen("      knuth_b", e ); }
  {
    using wide_t = unsigned long long ;
    independent_bits_engine<ranlux48, sizeof(wide_t)*8, wide_t> e{};
    messen("indep<ranlux>", e );
  }
  {
    using wide_t = unsigned long long;
    independent_bits_engine<
          default_random_engine,
          sizeof(wide_t)*8, wide_t>
      e {};
    messen("indep<default>", e );
  }
}

Listing 28.19: Eine Binomialverteilung

Book listing lst-0919-book.cpp:

// https://godbolt.org/z/hvM8K4oY6 
#include <random>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    static const size_t size = 10;
    default_random_engine e{};                // Zufallsgenerator
    vector<size_t> counts(size+1);
    binomial_distribution<int> muenzen{size}; // wirft 10 Münzen, 0- bis 10-mal Kopf
    for(auto i=120*1000; i>0; --i)
        ++counts[muenzen(e)];                 // Münzen werfen
    for(auto c : counts) cout<<" "<<c;
    cout << '\n';
    // Beispielausgabe:
    // 109 1159 5344 14043 24806 29505 24544 13973 5252 1150 115
}

Godbolt Listing lst-0919-godb.cpp, https://godbolt.org/z/hvM8K4oY6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hvM8K4oY6 
#include <random>
#include <vector>
#include <iostream>
using namespace std;
int main() {
    static const size_t size = 10;
    default_random_engine e{};                // Zufallsgenerator
    vector<size_t> counts(size+1);
    binomial_distribution<int> muenzen{size}; // wirft 10 Münzen, 0- bis 10-mal Kopf
    for(auto i=120*1000; i>0; --i)
        ++counts[muenzen(e)];                 // Münzen werfen
    for(auto c : counts) cout<<" "<<c;
    cout << '\n';
    // Beispielausgabe:
    // 109 1159 5344 14043 24806 29505 24544 13973 5252 1150 115
}

Listing 28.20: Eine »double«-Zufallszahl

Book listing lst-0920-book.cpp:

// https://godbolt.org/z/94McsP7PG 
#include <random>
#include <iostream>
int main() {
    std::default_random_engine e{};
    std::uniform_real_distribution<double> unif{3,7}; // im halboff. Intervall [3,7)
    double u = unif(e);                          // Zufallszahl ermitteln
    std::cout << u << '\n';                      // Beispielausgabe: 3.52615
}

Godbolt Listing lst-0920-godb.cpp, https://godbolt.org/z/94McsP7PG:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/94McsP7PG 
#include <random>
#include <iostream>
int main() {
    std::default_random_engine e{};
    std::uniform_real_distribution<double> unif{3,7}; // im halboff. Intervall [3,7)
    double u = unif(e);                          // Zufallszahl ermitteln
    std::cout << u << '\n';                      // Beispielausgabe: 3.52615
}

Listing 28.21: Generierungsparameter für jede Zufallszahl einzeln ändern

Book listing lst-0921-book.cpp:

// https://godbolt.org/z/xz64qK3e5 
#include <random>
#include <iostream>
int main() {
    std::default_random_engine e{};
    using Dstr = std::uniform_int_distribution<int>;       // gleichverteilte int
    Dstr karte{};                                          // Verteilung erzeugen
    for(int n=32; n>=1; --n)
      std::cout <<" "<< karte(e, Dstr::param_type{1,n} );  // Parameter erst hier
    std::cout << '\n';
    // Ausgabe zum Beispiel:
    // 1 5 23 14 15 6 2 17 17 22 9 11 17 1 1 10 11 1 6 1 6 8 6 9 7 4 1 4 2 3 2 1
}

Godbolt Listing lst-0921-godb.cpp, https://godbolt.org/z/xz64qK3e5:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xz64qK3e5 
#include <random>
#include <iostream>
int main() {
    std::default_random_engine e{};
    using Dstr = std::uniform_int_distribution<int>;       // gleichverteilte int
    Dstr karte{};                                          // Verteilung erzeugen
    for(int n=32; n>=1; --n)
      std::cout <<" "<< karte(e, Dstr::param_type{1,n} );  // Parameter erst hier
    std::cout << '\n';
    // Ausgabe zum Beispiel:
    // 1 5 23 14 15 6 2 17 17 22 9 11 17 1 1 10 11 1 6 1 6 8 6 9 7 4 1 4 2 3 2 1
}

GodboltId:173nr4xxd

Book listing lst-0926-book.cpp:

// https://godbolt.org/z/173nr4xxd 
sleep(10min);
sleep(std::chrono::minutes{10});
sleep(std::chrono::duration<unsigned long,std::ratio<60>>{10});

Godbolt Listing lst-0926-godb.cpp, https://godbolt.org/z/173nr4xxd:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/173nr4xxd 
sleep(10min);
sleep(std::chrono::minutes{10});
sleep(std::chrono::duration<unsigned long,std::ratio<60>>{10});

GodboltId:5snr1hq9b

Book listing lst-0927-book.cpp:

// https://godbolt.org/z/5snr1hq9b 
#include <chrono>
void sleep(std::chrono::seconds s) { // nimmt Sekunden als Dauer
    /* ... */
}
/* ... */
int main() {
    using namespace std::chrono; // Literale verfügbar machen
    sleep(10min);   // 10 Minuten warten, also 600 Sekunden
    sleep(10ms);    //                     (ERR)  10 Millisekunden? Mit Sekunden nicht abzubilden.
}

Godbolt Listing lst-0927-godb.cpp, https://godbolt.org/z/5snr1hq9b:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5snr1hq9b 
#include <chrono>
void sleep(std::chrono::seconds s) { // nimmt Sekunden als Dauer
    /* ... */
}
/* ... */
int main() {
    using namespace std::chrono; // Literale verfügbar machen
    sleep(10min);   // 10 Minuten warten, also 600 Sekunden
    sleep(10ms);    //                     (ERR)  10 Millisekunden? Mit Sekunden nicht abzubilden.
}

GodboltId:h8vsjxsME

Book listing lst-0929-book.cpp:

// https://godbolt.org/z/h8vsjxsME 
#include <cinttypes> // int64_t
namespace std { namespace chrono {
class seconds {
    int64_t sec_;
public:
    seconds() = default;
    // … etc …
};
} }

Godbolt Listing lst-0929-godb.cpp, https://godbolt.org/z/h8vsjxsME:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/h8vsjxsME 
#include <cinttypes> // int64_t
namespace std { namespace chrono {
class seconds {
    int64_t sec_;
public:
    seconds() = default;
    // … etc …
};
} }

Listing 28.22: Mit »seconds« können Sie rechnen.

Book listing lst-0934-book.cpp:

// https://godbolt.org/z/hPPrPT69h 
#include <chrono>
#include <iostream>
void sleep(std::chrono::seconds dur) {
    std::cout << dur.count() << "s\n";
    /* ... */
}
int main() {
    using namespace std::chrono;
    sleep(3);          //                     (ERR)  Fehler: keine implizite Konvertierung von int
    sleep(seconds{4}); // okay
    sleep(5s);         // okay
    seconds x{6};
    sleep(x);          // okay
    auto y = 10s;
    y += 20s;          // Inkrementieren mit Sekunden
    sleep(y);          // nun also 30s
    y = y - 6s;        // Subtraktion von Sekunden
    sleep(y);          // und nun nur noch 24s
    y /= 2;            // Division durch einen Skalar
    sleep(y);          // 12s
    sleep(y + 7);      //                     (ERR)  Fehler: seconds+int geht nicht
}

Godbolt Listing lst-0934-godb.cpp, https://godbolt.org/z/hPPrPT69h:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hPPrPT69h 
#include <chrono>
#include <iostream>
void sleep(std::chrono::seconds dur) {
    std::cout << dur.count() << "s\n";
    /* ... */
}
int main() {
    using namespace std::chrono;
    sleep(3);          //                     (ERR)  Fehler: keine implizite Konvertierung von int
    sleep(seconds{4}); // okay
    sleep(5s);         // okay
    seconds x{6};
    sleep(x);          // okay
    auto y = 10s;
    y += 20s;          // Inkrementieren mit Sekunden
    sleep(y);          // nun also 30s
    y = y - 6s;        // Subtraktion von Sekunden
    sleep(y);          // und nun nur noch 24s
    y /= 2;            // Division durch einen Skalar
    sleep(y);          // 12s
    sleep(y + 7);      //                     (ERR)  Fehler: seconds+int geht nicht
}

Listing 28.23: Sie können »seconds« vergleichen.

Book listing lst-0935-book.cpp:

// https://godbolt.org/z/8c1r5xrs5 
#include <chrono>
#include <iostream>
using std::chrono::operator""s;  // nur Literalsuffix verfügbar machen
constexpr auto limit = 10s;
void action(std::chrono::seconds dur) {
    if(dur <= limit) {          // vergleichen
       std::cout << dur.count() << "s\n";
    } else {
       std::cout << "zu lang!\n";
    }
}
int main() {
    action(4s);   // Ausgabe: 4s
    action(20s);  // Ausgabe: zu lang!
}

Godbolt Listing lst-0935-godb.cpp, https://godbolt.org/z/8c1r5xrs5:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8c1r5xrs5 
#include <chrono>
#include <iostream>
using std::chrono::operator""s;  // nur Literalsuffix verfügbar machen
constexpr auto limit = 10s;
void action(std::chrono::seconds dur) {
    if(dur <= limit) {          // vergleichen
       std::cout << dur.count() << "s\n";
    } else {
       std::cout << "zu lang!\n";
    }
}
int main() {
    action(4s);   // Ausgabe: 4s
    action(20s);  // Ausgabe: zu lang!
}

Listing 28.24: Automatische Umrechnung zwischen Zeiteinheiten

Book listing lst-0936-book.cpp:

// https://godbolt.org/z/qrs63vdz1 
#include <chrono>
#include <iostream>
int main() {
    using namespace std::chrono;             // Suffixe erlauben
    seconds mySecs = 121s;                   // seconds{121}
    std::cout << mySecs.count() << "s\n";    // Ausgabe: 121s
    milliseconds myMillis = mySecs;          // automatisch umgewandelt
    std::cout << myMillis.count() << "ms\n"; // Ausgabe: 121000ms
    nanoseconds myNanos = mySecs;
    std::cout << myNanos.count() << "ns\n"; // Ausgabe: 121000000000ns
    minutes myMinutesErr = mySecs;          //                     (ERR)  Fehler: Konvertierung mit Verlust
    minutes myMinutes = duration_cast<minutes>(mySecs); // explizit geht's
    std::cout<<myMinutes.count()<<"min\n";  // Ausgabe: 2min
}

Godbolt Listing lst-0936-godb.cpp, https://godbolt.org/z/qrs63vdz1:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qrs63vdz1 
#include <chrono>
#include <iostream>
int main() {
    using namespace std::chrono;             // Suffixe erlauben
    seconds mySecs = 121s;                   // seconds{121}
    std::cout << mySecs.count() << "s\n";    // Ausgabe: 121s
    milliseconds myMillis = mySecs;          // automatisch umgewandelt
    std::cout << myMillis.count() << "ms\n"; // Ausgabe: 121000ms
    nanoseconds myNanos = mySecs;
    std::cout << myNanos.count() << "ns\n"; // Ausgabe: 121000000000ns
    minutes myMinutesErr = mySecs;          //                     (ERR)  Fehler: Konvertierung mit Verlust
    minutes myMinutes = duration_cast<minutes>(mySecs); // explizit geht's
    std::cout<<myMinutes.count()<<"min\n";  // Ausgabe: 2min
}

Listing 28.26: Sie können Einheiten mischen.

Book listing lst-0937-book.cpp:

// https://godbolt.org/z/vTx4cdqzq 
#include <chrono>
#include <iostream>
void showDuration(std::chrono::milliseconds dur) {
    std::cout << dur.count() << "ms\n";
}
int main() {
    using namespace std::chrono;
    auto x = 2s;
    auto y = 3ms;
    showDuration(x + y); // Ausgabe: 2003ms
    showDuration(x - y); // Ausgabe: 1997ms
}

Godbolt Listing lst-0937-godb.cpp, https://godbolt.org/z/vTx4cdqzq:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vTx4cdqzq 
#include <chrono>
#include <iostream>
void showDuration(std::chrono::milliseconds dur) {
    std::cout << dur.count() << "ms\n";
}
int main() {
    using namespace std::chrono;
    auto x = 2s;
    auto y = 3ms;
    showDuration(x + y); // Ausgabe: 2003ms
    showDuration(x - y); // Ausgabe: 1997ms
}

Listing 28.27: Erstellen Sie neue Zeiteinheiten oder sparsamere Repräsentationen.

Book listing lst-0938-book.cpp:

// https://godbolt.org/z/5Wd1rKrMe 
#include <chrono>
#include <iostream>
using namespace std::chrono; using std::cout;
using seconds32 = duration<int32_t>;                // andere Repräsentation
using zehntag = duration<int,std::ratio<86400*10>>; // andere Zeiteinheit
using fseconds = duration<double>;                  // Fließkommarepräsentation
int main() {
  seconds32 s{5};
  cout << milliseconds(s).count() << "ms\n";
  zehntag z{1};
  hours h = z;                 // Umwandlung kostenlos
  cout << "1 Zehntag hat "<<h.count()<<" Stunden\n";              // …240…
  fseconds fs{23.75};
  cout << fs.count() << "s\n"; // Fließkommaausgabe
  auto printDur = [](fseconds f) { cout << f.count() << "s\n"; }; // Funktion
  printDur(45ms + 63us);       // Umwandlung in fseconds
  // Ausgabe: 0.045063s
}

Godbolt Listing lst-0938-godb.cpp, https://godbolt.org/z/5Wd1rKrMe:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/5Wd1rKrMe 
#include <chrono>
#include <iostream>
using namespace std::chrono; using std::cout;
using seconds32 = duration<int32_t>;                // andere Repräsentation
using zehntag = duration<int,std::ratio<86400*10>>; // andere Zeiteinheit
using fseconds = duration<double>;                  // Fließkommarepräsentation
int main() {
  seconds32 s{5};
  cout << milliseconds(s).count() << "ms\n";
  zehntag z{1};
  hours h = z;                 // Umwandlung kostenlos
  cout << "1 Zehntag hat "<<h.count()<<" Stunden\n";              // …240…
  fseconds fs{23.75};
  cout << fs.count() << "s\n"; // Fließkommaausgabe
  auto printDur = [](fseconds f) { cout << f.count() << "s\n"; }; // Funktion
  printDur(45ms + 63us);       // Umwandlung in fseconds
  // Ausgabe: 0.045063s
}

GodboltId:Gvz4crW75

Book listing lst-0939-book.cpp:

// https://godbolt.org/z/Gvz4crW75 
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
    year y{2021};
    std::cout << y << "\n";
    month m{October};
    auto result = m + months{3};   // 'months', nicht 'month': 3 Monate später
    std::cout << result << "\n";   // übergelaufen zu Januar
    weekday wd{Thursday};
    auto result = wd + days{4};    // 'days', nicht 'day': 4 Tage später
    std::cout << result << "\n";   // übergelaufen zu Montag
    weekday sun1{0};               // 0 ist Sonntag
    weekday sun2{7};               // 7 ist auch Sonntag
    std::cout << sun1 << "\t" << sun2 << "\n";
    weekday_indexed wdi{wd, 4};    // unbestimmter 4. Donnerstag
    std::cout << wdi << "\n";      // Ausgabe: Thu[4] — so gibt chrono 
                                   // unbestimmte Werte aus
}

Godbolt Listing lst-0939-godb.cpp, https://godbolt.org/z/Gvz4crW75:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Gvz4crW75 
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
    year y{2021};
    std::cout << y << "\n";
    month m{October};
    auto result = m + months{3};   // 'months', nicht 'month': 3 Monate später
    std::cout << result << "\n";   // übergelaufen zu Januar
    weekday wd{Thursday};
    auto result = wd + days{4};    // 'days', nicht 'day': 4 Tage später
    std::cout << result << "\n";   // übergelaufen zu Montag
    weekday sun1{0};               // 0 ist Sonntag
    weekday sun2{7};               // 7 ist auch Sonntag
    std::cout << sun1 << "\t" << sun2 << "\n";
    weekday_indexed wdi{wd, 4};    // unbestimmter 4. Donnerstag
    std::cout << wdi << "\n";      // Ausgabe: Thu[4] — so gibt chrono 
                                   // unbestimmte Werte aus
}

GodboltId:oaKbd9bd4

Book listing lst-0940-book.cpp:

// https://godbolt.org/z/oaKbd9bd4 
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
  year this_year{2021};
  year last_year{2020};
  year_month_day ymd{this_year, October, day{28}};
  std::cout << ymd << "\n";
  month_weekday mwd{November, Thursday[4]};  // in einem unbestimmten Jahr
  std::cout << mwd << "\n";                  // Ausgabe: Nov/Thu[4]
  month_day_last mdlast{February};      // letzter Tag eines unbestimmten Februars
  year_month_day_last leap{last_year, mdlast};         // Jahr hinzufügen
  year_month_day_last noleap{this_year, mdlast};       // Jahr hinzufügen
  std::cout << leap << "\t" << leap.day() << "\n";     // Ausgabe: 2020-02-29 29
  std::cout << noleap << "\t" << noleap.day() << "\n"; // Ausgabe: 2021-02-28 28
}

Godbolt Listing lst-0940-godb.cpp, https://godbolt.org/z/oaKbd9bd4:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oaKbd9bd4 
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
  year this_year{2021};
  year last_year{2020};
  year_month_day ymd{this_year, October, day{28}};
  std::cout << ymd << "\n";
  month_weekday mwd{November, Thursday[4]};  // in einem unbestimmten Jahr
  std::cout << mwd << "\n";                  // Ausgabe: Nov/Thu[4]
  month_day_last mdlast{February};      // letzter Tag eines unbestimmten Februars
  year_month_day_last leap{last_year, mdlast};         // Jahr hinzufügen
  year_month_day_last noleap{this_year, mdlast};       // Jahr hinzufügen
  std::cout << leap << "\t" << leap.day() << "\n";     // Ausgabe: 2020-02-29 29
  std::cout << noleap << "\t" << noleap.day() << "\n"; // Ausgabe: 2021-02-28 28
}

GodboltId:4s69W7qd3

Book listing lst-0942-book.cpp:

// https://godbolt.org/z/4s69W7qd3 
auto a_date = 2024y/11/14d;
auto b_date = 2024y/11/14;
auto c_date = 14d/11/2024;
auto d_date = November/14/2024;

Godbolt Listing lst-0942-godb.cpp, https://godbolt.org/z/4s69W7qd3:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4s69W7qd3 
auto a_date = 2024y/11/14d;
auto b_date = 2024y/11/14;
auto c_date = 14d/11/2024;
auto d_date = November/14/2024;

Listing 28.28: Ausgabe von Datum und Zeit mit format

Book listing lst-0944-book.cpp:

// https://godbolt.org/z/Md38b9zvf 
#include <chrono>
#include <iostream>
#include <format>
using namespace std::chrono;
int main() {
  auto ymd = last/February/2024;   // letzter Tag im Februar 2024: 29.2.2024
  std::cout << ymd << "\n";        // die Ausgabe mit << ist einfach
  std::cout << std::format("{:%Y-%m-%d}\n", ymd);  // format ist flexibler
  std::cout << std::format("{:%e. %B %y}\n", ymd); // viel flexibler!
}

Godbolt Listing lst-0944-godb.cpp, https://godbolt.org/z/Md38b9zvf:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Md38b9zvf 
#include <chrono>
#include <iostream>
#include <format>
using namespace std::chrono;
int main() {
  auto ymd = last/February/2024;   // letzter Tag im Februar 2024: 29.2.2024
  std::cout << ymd << "\n";        // die Ausgabe mit << ist einfach
  std::cout << std::format("{:%Y-%m-%d}\n", ymd);  // format ist flexibler
  std::cout << std::format("{:%e. %B %y}\n", ymd); // viel flexibler!
}

Listing 28.29: Immer der zweite Dienstag eines Monats

Book listing lst-0945-book.cpp:

// https://godbolt.org/z/19vf9jfTM 
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
    for (int mo = 1; mo <= 12; ++mo) {
        year_month_weekday patch_tues{mo/Tuesday[2]/2024y};
        year_month_day ymd{sys_days{patch_tues}};
        std::cout << ymd.month() << " " << ymd.day() << "\n";
    }
}

Godbolt Listing lst-0945-godb.cpp, https://godbolt.org/z/19vf9jfTM:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/19vf9jfTM 
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
    for (int mo = 1; mo <= 12; ++mo) {
        year_month_weekday patch_tues{mo/Tuesday[2]/2024y};
        year_month_day ymd{sys_days{patch_tues}};
        std::cout << ymd.month() << " " << ymd.day() << "\n";
    }
}

Listing 28.30: Umwandlung in eine zeitzonenbehaftete Zeit und die Ausnahmen

Book listing lst-0947-book.cpp:

// https://godbolt.org/z/hP7nhEW69 
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
  auto fruehl = local_days{31d/March/2024} + 2h + 1min;
  try {
      auto zt = zoned_time{"Europe/Berlin", fruehl};
  } catch (const nonexistent_local_time& e) {
      std::cout << e.what() << '\n'; // Ausnahme geworfen: existiert nicht
  }
  auto herbst = local_days{27d/October/2024} + 2h + 1min;
  try {
      auto zt = zoned_time{"Europe/Berlin", herbst};
  } catch (const ambiguous_local_time& e) {
     std::cout << e.what() << '\n'; // Ausnahme geworfen: existiert doppelt
  }
  std::cout << zoned_time{"Europe/Berlin", herbst, choose::earliest} << '\n';
  // Ausgabe: 2024-10-27 02:01:00 CEST
  std::cout << zoned_time{"Europe/Berlin", herbst, choose::latest} << '\n';
  // Ausgabe: 2024-10-27 02:01:00 CET
}

Godbolt Listing lst-0947-godb.cpp, https://godbolt.org/z/hP7nhEW69:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hP7nhEW69 
#include <chrono>
#include <iostream>
using namespace std::chrono;
int main() {
  auto fruehl = local_days{31d/March/2024} + 2h + 1min;
  try {
      auto zt = zoned_time{"Europe/Berlin", fruehl};
  } catch (const nonexistent_local_time& e) {
      std::cout << e.what() << '\n'; // Ausnahme geworfen: existiert nicht
  }
  auto herbst = local_days{27d/October/2024} + 2h + 1min;
  try {
      auto zt = zoned_time{"Europe/Berlin", herbst};
  } catch (const ambiguous_local_time& e) {
     std::cout << e.what() << '\n'; // Ausnahme geworfen: existiert doppelt
  }
  std::cout << zoned_time{"Europe/Berlin", herbst, choose::earliest} << '\n';
  // Ausgabe: 2024-10-27 02:01:00 CEST
  std::cout << zoned_time{"Europe/Berlin", herbst, choose::latest} << '\n';
  // Ausgabe: 2024-10-27 02:01:00 CET
}

Listing 28.31: Die Zeitzonendatenbank

Book listing lst-0948-book.cpp:

// https://godbolt.org/z/YTKK3vT7s 
#include <chrono>
#include <iostream>
#include <ranges> // views::transform, views::filter
#include <algorithm> // ranges::for_each
using namespace std; namespace c = std::chrono;
namespace v = std::views; namespace r = std::ranges;
int main() {
  auto show_name = [](const string_view name) { cout << name << ' '; };
  const auto& db = c::get_tzdb();
  auto names = db.zones
   | v::transform([](const c::time_zone& z) {return z.name();})
   | v::filter([](const string_view name) {
       return name.starts_with("Europe/Be");});
  r::for_each(names, show_name);
  cout << " <- Europe/Be*\n"; // Ausgabe: Europe/Belgrade Europe/Berlin
  r::for_each(
   db.links
   | v::filter([](const c::time_zone_link& l){
       return l.target()=="Europe/Berlin";})
   | v::transform([](const c::time_zone_link& l)->string_view {
       return l.name();})
   , show_name);
  cout << " <- Links nach Europe/Berlin\n"; // Ausgabe: Arctic/Longyearbyen …
}

Godbolt Listing lst-0948-godb.cpp, https://godbolt.org/z/YTKK3vT7s:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YTKK3vT7s 
#include <chrono>
#include <iostream>
#include <ranges> // views::transform, views::filter
#include <algorithm> // ranges::for_each
using namespace std; namespace c = std::chrono;
namespace v = std::views; namespace r = std::ranges;
int main() {
  auto show_name = [](const string_view name) { cout << name << ' '; };
  const auto& db = c::get_tzdb();
  auto names = db.zones
   | v::transform([](const c::time_zone& z) {return z.name();})
   | v::filter([](const string_view name) {
       return name.starts_with("Europe/Be");});
  r::for_each(names, show_name);
  cout << " <- Europe/Be*\n"; // Ausgabe: Europe/Belgrade Europe/Berlin
  r::for_each(
   db.links
   | v::filter([](const c::time_zone_link& l){
       return l.target()=="Europe/Berlin";})
   | v::transform([](const c::time_zone_link& l)->string_view {
       return l.name();})
   , show_name);
  cout << " <- Links nach Europe/Berlin\n"; // Ausgabe: Arctic/Longyearbyen …
}

GodboltId:YsjvxTKGj

Book listing lst-0949-book.cpp:

// https://godbolt.org/z/YsjvxTKGj 
#include <iostream>
#include <ratio>
using std::cout; using std::endl;
int main() {
  using einDrittel = std::ratio<1,3>;
  using zweiViertel = std::ratio<2,4>;
  cout << einDrittel::num << "/" << einDrittel::den << endl;   // Ausgabe: 1/3
  cout << zweiViertel::num << "/" << zweiViertel::den << endl; // Ausgabe: 1/2
  using sum = std::ratio_add<einDrittel,zweiViertel>;          // addieren
  cout << sum::num << "/" << sum::den;                         // Ausgabe: 5/6
}

Godbolt Listing lst-0949-godb.cpp, https://godbolt.org/z/YsjvxTKGj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YsjvxTKGj 
#include <iostream>
#include <ratio>
using std::cout; using std::endl;
int main() {
  using einDrittel = std::ratio<1,3>;
  using zweiViertel = std::ratio<2,4>;
  cout << einDrittel::num << "/" << einDrittel::den << endl;   // Ausgabe: 1/3
  cout << zweiViertel::num << "/" << zweiViertel::den << endl; // Ausgabe: 1/2
  using sum = std::ratio_add<einDrittel,zweiViertel>;          // addieren
  cout << sum::num << "/" << sum::den;                         // Ausgabe: 5/6
}

GodboltId:q1znGWb85

Book listing lst-0954-book.cpp:

// https://godbolt.org/z/q1znGWb85 
#include <iostream>
#include <chrono>
int main() {
    using namespace std::chrono;
    time_point<system_clock, seconds> t1{10000s};
    time_point<system_clock, seconds> t2{50000s};
    auto dur = t2 - t1;
    std::cout << duration_cast<hours>(dur).count() << "h"; // Ausgabe: 11h
}

Godbolt Listing lst-0954-godb.cpp, https://godbolt.org/z/q1znGWb85:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/q1znGWb85 
#include <iostream>
#include <chrono>
int main() {
    using namespace std::chrono;
    time_point<system_clock, seconds> t1{10000s};
    time_point<system_clock, seconds> t2{50000s};
    auto dur = t2 - t1;
    std::cout << duration_cast<hours>(dur).count() << "h"; // Ausgabe: 11h
}

Listing 28.32: Einfache Zeitmessung eines Funktionsaufrufs

Book listing lst-0958-book.cpp:

// https://godbolt.org/z/8hxd9bPb4 
#include <iostream>
#include <chrono>
long fib(long n) { return n<2L ? 1L : fib(n-1L)+fib(n-2L); }
int main() {
    using namespace std::chrono;
    auto t0 = steady_clock::now();  // Auf die Plätze, fertig …
    auto res = fib(17);             // … los!
    auto t1 = steady_clock::now();  // Stopp!
    std::cout << "Ergebnis: " << res << "\n"; // Ausgabe: Ergebnis: 2584
    std::cout << "Zeit: " << nanoseconds{t1-t0}.count() << "ns\n";
    // Ausgabe: Zeit: 50727ns (z. B.)
}

Godbolt Listing lst-0958-godb.cpp, https://godbolt.org/z/8hxd9bPb4:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8hxd9bPb4 
#include <iostream>
#include <chrono>
long fib(long n) { return n<2L ? 1L : fib(n-1L)+fib(n-2L); }
int main() {
    using namespace std::chrono;
    auto t0 = steady_clock::now();  // Auf die Plätze, fertig …
    auto res = fib(17);             // … los!
    auto t1 = steady_clock::now();  // Stopp!
    std::cout << "Ergebnis: " << res << "\n"; // Ausgabe: Ergebnis: 2584
    std::cout << "Zeit: " << nanoseconds{t1-t0}.count() << "ns\n";
    // Ausgabe: Zeit: 50727ns (z. B.)
}

GodboltId:rz38hc1cx

Book listing lst-0959-book.cpp:

// https://godbolt.org/z/rz38hc1cx 
auto res = fib(45);
// …
std::cout << "Zeit: " << duration_cast<seconds>(t1-t0).count() << "s\n";
// Ausgabe: Zeit: 7s (z. B.)
std::cout << "Zeit: " << duration<double>{t1-t0}.count() << "s\n";
// Ausgabe: Zeit: 7.35303s (z. B.)
}

Godbolt Listing lst-0959-godb.cpp, https://godbolt.org/z/rz38hc1cx:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rz38hc1cx 
auto res = fib(45);
// …
std::cout << "Zeit: " << duration_cast<seconds>(t1-t0).count() << "s\n";
// Ausgabe: Zeit: 7s (z. B.)
std::cout << "Zeit: " << duration<double>{t1-t0}.count() << "s\n";
// Ausgabe: Zeit: 7.35303s (z. B.)
}

GodboltId:1xbhhTdEv

Book listing lst-0960-book.cpp:

// https://godbolt.org/z/1xbhhTdEv 
#include <iostream>
#include <chrono>
int main() {
    using namespace std::chrono;
    auto tp = time_point_cast<seconds>(system_clock::now());
    auto d = tp.time_since_epoch();
    std::cout << d.count() << "s\n";
    std::cout << duration<double,std::ratio<86400>>{d}.count() << "days\n";
}

Godbolt Listing lst-0960-godb.cpp, https://godbolt.org/z/1xbhhTdEv:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1xbhhTdEv 
#include <iostream>
#include <chrono>
int main() {
    using namespace std::chrono;
    auto tp = time_point_cast<seconds>(system_clock::now());
    auto d = tp.time_since_epoch();
    std::cout << d.count() << "s\n";
    std::cout << duration<double,std::ratio<86400>>{d}.count() << "days\n";
}

GodboltId:o359TThMj

Book listing lst-0961-book.cpp:

// https://godbolt.org/z/o359TThMj 
#include <iostream>
#include <string>
#include <chrono>
#include <complex>
using std::cout;
int main() {
    { using namespace std;
      cout << "string"s << "\n";           // string
      cout << (1.2+3.4i) << "\n";          // complex
      }
    { using namespace std::chrono;
      cout << (35ms).count() << "ms\n";    // chrono
      }
    { using namespace std::literals;
      cout << (41s).count() << "ms\n";     // chrono seconds
      cout << "text"s << "\n";             // string
    }
    { using namespace std::chrono; 
      cout << (4h).count() << "h\n";       // chrono hours
    }
    { using namespace std::literals::chrono_literals; 
      cout << (16min).count() << "min\n";  // chrono minutes
    }
    { using std::literals::string_literals::operator""s; 
      cout << "buchstaben"s << "\n";        // string
    }
}

Godbolt Listing lst-0961-godb.cpp, https://godbolt.org/z/o359TThMj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/o359TThMj 
#include <iostream>
#include <string>
#include <chrono>
#include <complex>
using std::cout;
int main() {
    { using namespace std;
      cout << "string"s << "\n";           // string
      cout << (1.2+3.4i) << "\n";          // complex
      }
    { using namespace std::chrono;
      cout << (35ms).count() << "ms\n";    // chrono
      }
    { using namespace std::literals;
      cout << (41s).count() << "ms\n";     // chrono seconds
      cout << "text"s << "\n";             // string
    }
    { using namespace std::chrono; 
      cout << (4h).count() << "h\n";       // chrono hours
    }
    { using namespace std::literals::chrono_literals; 
      cout << (16min).count() << "min\n";  // chrono minutes
    }
    { using std::literals::string_literals::operator""s; 
      cout << "buchstaben"s << "\n";        // string
    }
}

Listing 28.34: Sehr einfaches Beispiel dafür, wie man den Erfolg einer Operation prüfen kann

Book listing lst-0962-book.cpp:

// https://godbolt.org/z/1xnY8vd8Y 
#include <system_error> // error_code
#include <string>
void create_dir(const std::string& pathname, std::error_code& ec);
void run() {
  std::error_code ec;
  create_dir("/some/path", ec);
  if(!ec) {  // Erfolg …
  } else {   // Misserfolg …
  }
}

Godbolt Listing lst-0962-godb.cpp, https://godbolt.org/z/1xnY8vd8Y:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1xnY8vd8Y 
#include <system_error> // error_code
#include <string>
void create_dir(const std::string& pathname, std::error_code& ec);
void run() {
  std::error_code ec;
  create_dir("/some/path", ec);
  if(!ec) {  // Erfolg …
  } else {   // Misserfolg …
  }
}

Listing 28.35: Vergleich von »error_code« mit »error_condition«

Book listing lst-0963-book.cpp:

// https://godbolt.org/z/TPWc5nexq 
#include <system_error> // error_code, errc
#include <string>
void create_dir(const std::string& pathname, std::error_code& ec);
void run() {
  std::error_code ec;
  create_dir("/some/path", ec);
  if(ec == std::errc::file_exists) {   // speziell …
  } else if(!ec) {                     // Erfolg …
  } else {                             // Misserfolg …
  }
}

Godbolt Listing lst-0963-godb.cpp, https://godbolt.org/z/TPWc5nexq:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TPWc5nexq 
#include <system_error> // error_code, errc
#include <string>
void create_dir(const std::string& pathname, std::error_code& ec);
void run() {
  std::error_code ec;
  create_dir("/some/path", ec);
  if(ec == std::errc::file_exists) {   // speziell …
  } else if(!ec) {                     // Erfolg …
  } else {                             // Misserfolg …
  }
}

Listing 28.36: Überladungen von »operator==()« (abgekürzt)

Book listing lst-0964-book.cpp:

bool operator==
   (const error_code&    lhs, const error_code&      rhs) noexcept;
(const error_code&      lhs, const error_condition& rhs) noexcept;
(const error_condition& lhs, const error_code&      rhs) noexcept;
(const error_condition& lhs, const error_condition& rhs) noexcept;

Listing 28.37: Definition von »enum class errc«

Book listing lst-0965-book.cpp:

enum class errc {
  address_family_not_supported,
  address_in_use,
  // ...
  value_too_large,
  wrong_protocol_type,
};

Listing 28.38: Spezialisierung von »is_error_condition_enum« für »errc«

Book listing lst-0966-book.cpp:

template <>
struct is_error_condition_enum<errc> : true_type {};

Listing 28.39: Unter den Überladungen von make_error_condition ist auch eine mit »errc«.

Book listing lst-0967-book.cpp:

error_condition make_error_condition(errc c) noexcept {
  return error_condition(
      static_cast<int>(e),
      generic_category());
}
error_condition make_error_condition(io_errc c) noexcept /*...*/
error_condition make_error_condition(future_errc c) noexcept /*...*/

Listing 28.40: Erzeugung systemspezifischer Fehlercodes in einem portablen Programm

Book listing lst-0968-book.cpp:

// https://godbolt.org/z/n4v78WWod 
#include <system_error>
#include <string>

void create_dir(const std::string& pathname, std::error_code& ec) {
#if defined(_WIN32)
  // Windows-Implementierung, mit Windows-Fehlercodes
#elif defined(linux)
  // Linux-Implementierung, mit Linux-Fehlercodes
#else
  // allgemeingültiger 'generischer' Fall
  ec = std::make_error_code(std::errc::not_supported);
#endif
}

Godbolt Listing lst-0968-godb.cpp, https://godbolt.org/z/n4v78WWod:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/n4v78WWod 
#include <system_error>
#include <string>

void create_dir(const std::string& pathname, std::error_code& ec) {
#if defined(_WIN32)
  // Windows-Implementierung, mit Windows-Fehlercodes
#elif defined(linux)
  // Linux-Implementierung, mit Linux-Fehlercodes
#else
  // allgemeingültiger 'generischer' Fall
  ec = std::make_error_code(std::errc::not_supported);
#endif
}

GodboltId:vxTxT4ajW

Book listing lst-0969-book.cpp:

// https://godbolt.org/z/vxTxT4ajW 
#include <system_error>
#include <iostream>
using std::error_code; using std::system_category;
namespace mylib {
    // eigene Errorcodes
    enum class errc { LOAD_ERR = 1, UNLOAD_ERR = 2, OTHER_ERR = 3 };
    error_code make_error_code(errc ec) {
        switch(ec) {
        case errc::LOAD_ERR: return error_code((int)ec, system_category());
        case errc::UNLOAD_ERR: return error_code((int)ec, system_category());
        case errc::OTHER_ERR: return error_code((int)ec, system_category());
        }
    }
    error_code run(int arg) {
        if(arg == 667) {
            return make_error_code(errc::OTHER_ERR);
        }
        return error_code{}; // alles gut.
    }
}
int main() {
    std::error_code ec = mylib::run(667);
    if(!ec) {
        std::cout << "Klasse, klappt!\n";
    } else if (ec == mylib::make_error_code(mylib::errc::OTHER_ERR)) {
        std::cout << "Anderer Fehler\n";
    } else {
        std::cout << "Nix los hier\n" << ec;
    }
}

Godbolt Listing lst-0969-godb.cpp, https://godbolt.org/z/vxTxT4ajW:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/vxTxT4ajW 
#include <system_error>
#include <iostream>
using std::error_code; using std::system_category;
namespace mylib {
    // eigene Errorcodes
    enum class errc { LOAD_ERR = 1, UNLOAD_ERR = 2, OTHER_ERR = 3 };
    error_code make_error_code(errc ec) {
        switch(ec) {
        case errc::LOAD_ERR: return error_code((int)ec, system_category());
        case errc::UNLOAD_ERR: return error_code((int)ec, system_category());
        case errc::OTHER_ERR: return error_code((int)ec, system_category());
        }
    }
    error_code run(int arg) {
        if(arg == 667) {
            return make_error_code(errc::OTHER_ERR);
        }
        return error_code{}; // alles gut.
    }
}
int main() {
    std::error_code ec = mylib::run(667);
    if(!ec) {
        std::cout << "Klasse, klappt!\n";
    } else if (ec == mylib::make_error_code(mylib::errc::OTHER_ERR)) {
        std::cout << "Anderer Fehler\n";
    } else {
        std::cout << "Nix los hier\n" << ec;
    }
}

GodboltId:a8zP84j1x

Book listing lst-0971-book.cpp:

// https://godbolt.org/z/a8zP84j1x 
#include <thread>
#include <iostream>
#include <system_error>
int main() {
    try {
        std::thread().detach(); // das wird fehlschlagen
    } catch(std::system_error& e) {
        std::cout
            << "system_error mit Code:" << e.code()
            << " Meldung:" << e.what()
            << '\n';
    }
}

Godbolt Listing lst-0971-godb.cpp, https://godbolt.org/z/a8zP84j1x:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a8zP84j1x 
#include <thread>
#include <iostream>
#include <system_error>
int main() {
    try {
        std::thread().detach(); // das wird fehlschlagen
    } catch(std::system_error& e) {
        std::cout
            << "system_error mit Code:" << e.code()
            << " Meldung:" << e.what()
            << '\n';
    }
}

GodboltId:cjh93oPcr

Book listing lst-0972-book.cpp:

// https://godbolt.org/z/cjh93oPcr 
#include <iostream>
#include <system_error> // std::make_error_condition, std::ios_errc
int main () {
  // umschalten auf Exceptions:
  std::cin.exceptions (std::ios::failbit|std::ios::badbit);
  try {
    std::cin.rdbuf(nullptr);       // löst eine Exception aus
  } catch (std::ios::failure& e) { // abgeleitet von system_error
    std::cerr << "Fehler: ";
    if (e.code() == std::make_error_condition(std::io_errc::stream)) {
      std::cerr << "stream\n";
    } else {
      std::cerr << "andere\n";
    }
  }
}

Godbolt Listing lst-0972-godb.cpp, https://godbolt.org/z/cjh93oPcr:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/cjh93oPcr 
#include <iostream>
#include <system_error> // std::make_error_condition, std::ios_errc
int main () {
  // umschalten auf Exceptions:
  std::cin.exceptions (std::ios::failbit|std::ios::badbit);
  try {
    std::cin.rdbuf(nullptr);       // löst eine Exception aus
  } catch (std::ios::failure& e) { // abgeleitet von system_error
    std::cerr << "Fehler: ";
    if (e.code() == std::make_error_condition(std::io_errc::stream)) {
      std::cerr << "stream\n";
    } else {
      std::cerr << "andere\n";
    }
  }
}

Listing 28.41: Nutzen Sie »typeindex« für verlässliche Typinformationen.

Book listing lst-0973-book.cpp:

// https://godbolt.org/z/x1dq1Wof6 
#include <iostream>
#include <typeinfo>
#include <typeindex>
#include <map>
#include <string>
struct Base {
    virtual ~Base() {}
};
struct Derived_One : public Base {};
struct Derived_Two : public Base {};
int main() {
  using std::string; using std::cout; using std::type_index;
  std::map<std::type_index, string> namen {
      { type_index(typeid(int)), "int" },
      { type_index(typeid(double)), "double" },
      { type_index(typeid(Base)), "Base" },
      { type_index(typeid(Derived_One)), "Derived_One" },
      { type_index(typeid(Derived_Two)), "Derived_Two" },
      { type_index(typeid(string)), "string" },
      { type_index(typeid(string::const_iterator)), "string" },
  };
  namen[type_index(typeid(namen))] = "namen-map";
  int ganz;
  double fliessend;
  Base base{};
  Base *one = new Derived_One{};
  Base *two = new Derived_Two{};
  // typeid.name() ist implementierungs- und laufzeitabhängig:
  cout << typeid(ganz).name() << '\n';      // Bei mir: i
  cout << typeid(fliessend).name() << '\n'; // Bei mir: d
  cout << typeid(base).name() << '\n';      // Bei mir: 4Base
  cout << typeid(*one).name() << '\n';      // Bei mir: 11Derived_One
  cout << typeid(*two).name() << '\n';      // Bei mir: 11Derived_Two
  cout << typeid(string).name() << '\n';    // Bei mir: Ss
  cout << typeid(string{"Welt"}.begin()).name() << '\n';
      // Bei mir: N9__gnu_cxx17__normal_iteratorIPcSsEE
  cout << typeid(namen).name() << '\n';
      // Bei mir: St3mapISt10type_indexSsSt4lessIS0_ESaISt4pairIKS0_SsEEE
  cout << typeid(666/0).name() << '\n'; // Ausdruck wird nicht ausgeführt! Bei mir: i
  // type_index macht type_infos vergleichbar:
  cout << namen[type_index(typeid(ganz))] << '\n';      // Ausgabe: int
  cout << namen[type_index(typeid(fliessend))] << '\n'; // Ausgabe: double
  cout << namen[type_index(typeid(base))] << '\n';      // Ausgabe: Base
  cout << namen[type_index(typeid(*one))] << '\n';      // Ausgabe: Derived_One
  cout << namen[type_index(typeid(*two))] << '\n';      // Ausgabe: Derived_Two
  cout << namen[type_index(typeid(string))] << '\n';    // Ausgabe: string
  cout << namen[type_index(typeid(namen))] << '\n';     // Ausgabe: namen-map
}

Godbolt Listing lst-0973-godb.cpp, https://godbolt.org/z/x1dq1Wof6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/x1dq1Wof6 
#include <iostream>
#include <typeinfo>
#include <typeindex>
#include <map>
#include <string>
struct Base {
    virtual ~Base() {}
};
struct Derived_One : public Base {};
struct Derived_Two : public Base {};
int main() {
  using std::string; using std::cout; using std::type_index;
  std::map<std::type_index, string> namen {
      { type_index(typeid(int)), "int" },
      { type_index(typeid(double)), "double" },
      { type_index(typeid(Base)), "Base" },
      { type_index(typeid(Derived_One)), "Derived_One" },
      { type_index(typeid(Derived_Two)), "Derived_Two" },
      { type_index(typeid(string)), "string" },
      { type_index(typeid(string::const_iterator)), "string" },
  };
  namen[type_index(typeid(namen))] = "namen-map";
  int ganz;
  double fliessend;
  Base base{};
  Base *one = new Derived_One{};
  Base *two = new Derived_Two{};
  // typeid.name() ist implementierungs- und laufzeitabhängig:
  cout << typeid(ganz).name() << '\n';      // Bei mir: i
  cout << typeid(fliessend).name() << '\n'; // Bei mir: d
  cout << typeid(base).name() << '\n';      // Bei mir: 4Base
  cout << typeid(*one).name() << '\n';      // Bei mir: 11Derived_One
  cout << typeid(*two).name() << '\n';      // Bei mir: 11Derived_Two
  cout << typeid(string).name() << '\n';    // Bei mir: Ss
  cout << typeid(string{"Welt"}.begin()).name() << '\n';
      // Bei mir: N9__gnu_cxx17__normal_iteratorIPcSsEE
  cout << typeid(namen).name() << '\n';
      // Bei mir: St3mapISt10type_indexSsSt4lessIS0_ESaISt4pairIKS0_SsEEE
  cout << typeid(666/0).name() << '\n'; // Ausdruck wird nicht ausgeführt! Bei mir: i
  // type_index macht type_infos vergleichbar:
  cout << namen[type_index(typeid(ganz))] << '\n';      // Ausgabe: int
  cout << namen[type_index(typeid(fliessend))] << '\n'; // Ausgabe: double
  cout << namen[type_index(typeid(base))] << '\n';      // Ausgabe: Base
  cout << namen[type_index(typeid(*one))] << '\n';      // Ausgabe: Derived_One
  cout << namen[type_index(typeid(*two))] << '\n';      // Ausgabe: Derived_Two
  cout << namen[type_index(typeid(string))] << '\n';    // Ausgabe: string
  cout << namen[type_index(typeid(namen))] << '\n';     // Ausgabe: namen-map
}

Listing 28.42: Boosts »demangled_name« ist für die Ausgabe von Typnamen extrem nützlich.

Book listing lst-0974-book.cpp:

// https://godbolt.org/z/n54566cqT 
#include <iostream>
#include <typeinfo>
#include <string>
#include <map>
#include <boost/core/typeinfo.hpp>
int main() {
  using std::string; using std::cout;
  std::map<int, string> namen;
  int ganz;
  double fliessend;
  // demangled_name
  using boost::core::demangled_name;
  cout<<demangled_name(BOOST_CORE_TYPEID(ganz))<<'\n';      // Ausgabe: int
  cout<<demangled_name(BOOST_CORE_TYPEID(fliessend))<<'\n'; // Ausgabe: double
  cout<<demangled_name(BOOST_CORE_TYPEID(string))<<'\n';  // Ausgabe: std::string
  cout<<demangled_name(BOOST_CORE_TYPEID(string{}.begin()))<<'\n';
  // Ausgabe: __gnu_cxx::__normal_iterator<char*, std::string>
  cout<<demangled_name(BOOST_CORE_TYPEID(namen))<<'\n';
  // Ausgabe: std::map<int, std::string, std::less<int>,
  //                                                         std::allocator<std::pair<int const, std::string> > >
  cout<<demangled_name(BOOST_CORE_TYPEID(666/0))<<'\n';  // Ausgabe: int
}

Godbolt Listing lst-0974-godb.cpp, https://godbolt.org/z/n54566cqT:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/n54566cqT 
#include <iostream>
#include <typeinfo>
#include <string>
#include <map>
#include <boost/core/typeinfo.hpp>
int main() {
  using std::string; using std::cout;
  std::map<int, string> namen;
  int ganz;
  double fliessend;
  // demangled_name
  using boost::core::demangled_name;
  cout<<demangled_name(BOOST_CORE_TYPEID(ganz))<<'\n';      // Ausgabe: int
  cout<<demangled_name(BOOST_CORE_TYPEID(fliessend))<<'\n'; // Ausgabe: double
  cout<<demangled_name(BOOST_CORE_TYPEID(string))<<'\n';  // Ausgabe: std::string
  cout<<demangled_name(BOOST_CORE_TYPEID(string{}.begin()))<<'\n';
  // Ausgabe: __gnu_cxx::__normal_iterator<char*, std::string>
  cout<<demangled_name(BOOST_CORE_TYPEID(namen))<<'\n';
  // Ausgabe: std::map<int, std::string, std::less<int>,
  //                                                         std::allocator<std::pair<int const, std::string> > >
  cout<<demangled_name(BOOST_CORE_TYPEID(666/0))<<'\n';  // Ausgabe: int
}

GodboltId:Y3GsPd97d

Book listing lst-0976-book.cpp:

// https://godbolt.org/z/Y3GsPd97d 
#include <set>
#include <string>
struct Drachen {
    std::string name_;
};
namespace std {
    template<> struct less<Drachen> { // Templatespezialisierung
        bool operator()(const Drachen &lhs, const Drachen &rhs) const {
            return lhs.name_ < rhs.name_;
} }; }
int main() {
  std::set<Drachen> drachen {
    Drachen{"Smaug"},Drachen{"Glaurung"},
        Drachen{"Ancalagon"},Drachen{"Scatha"}};
}

Godbolt Listing lst-0976-godb.cpp, https://godbolt.org/z/Y3GsPd97d:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Y3GsPd97d 
#include <set>
#include <string>
struct Drachen {
    std::string name_;
};
namespace std {
    template<> struct less<Drachen> { // Templatespezialisierung
        bool operator()(const Drachen &lhs, const Drachen &rhs) const {
            return lhs.name_ < rhs.name_;
} }; }
int main() {
  std::set<Drachen> drachen {
    Drachen{"Smaug"},Drachen{"Glaurung"},
        Drachen{"Ancalagon"},Drachen{"Scatha"}};
}

Listing 28.43: Dieser Taschenrechner bildet Tasten auf Funktoren ab.

Book listing lst-0977-book.cpp:

// https://godbolt.org/z/j85P7b3oq 
#include <string>
#include <vector>
#include <iostream>
#include <map>
#include <functional>
std::map<char,std::function<int(int,int)>> binOps { // zweistellige Operatoren
    {'+', std::plus<int>{} },
    {'-', std::minus<int>{} },
    {'*', std::multiplies<int>{} },
    {'/', std::divides<int>{} },
    {'%', std::modulus<int>{} },
    };
std::map<char,std::function<int(int)>> unOps { };    // einstellige Operatoren
auto val = [](auto n) { return [n](){ return n; };}; // gibt ein Lambda zurück
std::map<char,std::function<int()>> zeroOps {        // nullstellige Operatoren
  {'0', val(0)}, {'1', val(1)}, {'2', val(2)}, {'3', val(3)}, {'4', val(4)},
  {'5', val(5)}, {'6', val(6)}, {'7', val(7)}, {'8', val(8)}, {'9', val(9)},
  };
std::map<char,std::function<void(std::vector<int>&)>> stapelOps { 
  { ' ', [](auto &stapel) { } },           // keine Operation
  { 'c', [](auto &stapel) { stapel.clear(); } }, // Stapel ganz löschen
  { ':', [](auto &stapel) {                // obersten zwei Elemente vertauschen
            auto top = stapel.back(); stapel.pop_back();
            auto second = stapel.back(); stapel.pop_back();
            stapel.push_back(top);
            stapel.push_back(second);
  } },
  { '=', [](auto &stapel) {                // ganzen Stapel ausgeben
            for(int elem : stapel) { std::cout << elem; }
            std::cout << "\n";
  } },
};
void rechner(std::string input) {
  std::vector<int> stapel {};
  for(char c : input) {
    int top, second;
    if(auto it = unOps.find(c); it != unOps.end()) {
      // falls einstelliger Operator …
      auto func = it->second;
      top = stapel.back(); stapel.pop_back(); // … hole oberstes Element
      stapel.push_back(func(top));         // … wende func an, Ergebnis auf Stapel
    } else if(auto it = binOps.find(c); it != binOps.end()) {
      // falls zweistelliger Operator …
      auto func = it->second;
      top = stapel.back(); stapel.pop_back(); // … hole die obersten 2 Elemente
      second = stapel.back(); stapel.pop_back();
      stapel.push_back(func(second, top)); // … wende func an, Ergebnis auf Stapel
    } else if(auto it = zeroOps.find(c); it !=zeroOps.end()) {
      // falls nullstelliger Operator …
      auto func = it->second;
      stapel.push_back(func());            // … Ergebnis von func auf Stapel
    } else if(auto it = stapelOps.find(c); it !=stapelOps.end()) {
      // falls Stapeloperator
      auto func = it->second;
      func(stapel);                        // … wende func auf Stapel an
    } else {
      std::cout << "\n'" << c << "' verstehe ich nicht.\n";
    }
  } /* for c */
}
int main(int argc, const char* argv[]) {
    if(argc > 1) {
        rechner(argv[1]);
    } else {
        // 3+4*5+6 mit Punkt- vor Strichrechnung ergibt 29
        rechner("345*+6+=");
    }
    rechner("93-=");                     // 9 – 3 = Ausgabe: 6
    rechner("82/=");                     // 8 / 2 = Ausgabe: 4
    rechner("92%=");                     // 9 % 2 = Ausgabe: 1
}

Godbolt Listing lst-0977-godb.cpp, https://godbolt.org/z/j85P7b3oq:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/j85P7b3oq 
#include <string>
#include <vector>
#include <iostream>
#include <map>
#include <functional>
std::map<char,std::function<int(int,int)>> binOps { // zweistellige Operatoren
    {'+', std::plus<int>{} },
    {'-', std::minus<int>{} },
    {'*', std::multiplies<int>{} },
    {'/', std::divides<int>{} },
    {'%', std::modulus<int>{} },
    };
std::map<char,std::function<int(int)>> unOps { };    // einstellige Operatoren
auto val = [](auto n) { return [n](){ return n; };}; // gibt ein Lambda zurück
std::map<char,std::function<int()>> zeroOps {        // nullstellige Operatoren
  {'0', val(0)}, {'1', val(1)}, {'2', val(2)}, {'3', val(3)}, {'4', val(4)},
  {'5', val(5)}, {'6', val(6)}, {'7', val(7)}, {'8', val(8)}, {'9', val(9)},
  };
std::map<char,std::function<void(std::vector<int>&)>> stapelOps { 
  { ' ', [](auto &stapel) { } },           // keine Operation
  { 'c', [](auto &stapel) { stapel.clear(); } }, // Stapel ganz löschen
  { ':', [](auto &stapel) {                // obersten zwei Elemente vertauschen
            auto top = stapel.back(); stapel.pop_back();
            auto second = stapel.back(); stapel.pop_back();
            stapel.push_back(top);
            stapel.push_back(second);
  } },
  { '=', [](auto &stapel) {                // ganzen Stapel ausgeben
            for(int elem : stapel) { std::cout << elem; }
            std::cout << "\n";
  } },
};
void rechner(std::string input) {
  std::vector<int> stapel {};
  for(char c : input) {
    int top, second;
    if(auto it = unOps.find(c); it != unOps.end()) {
      // falls einstelliger Operator …
      auto func = it->second;
      top = stapel.back(); stapel.pop_back(); // … hole oberstes Element
      stapel.push_back(func(top));         // … wende func an, Ergebnis auf Stapel
    } else if(auto it = binOps.find(c); it != binOps.end()) {
      // falls zweistelliger Operator …
      auto func = it->second;
      top = stapel.back(); stapel.pop_back(); // … hole die obersten 2 Elemente
      second = stapel.back(); stapel.pop_back();
      stapel.push_back(func(second, top)); // … wende func an, Ergebnis auf Stapel
    } else if(auto it = zeroOps.find(c); it !=zeroOps.end()) {
      // falls nullstelliger Operator …
      auto func = it->second;
      stapel.push_back(func());            // … Ergebnis von func auf Stapel
    } else if(auto it = stapelOps.find(c); it !=stapelOps.end()) {
      // falls Stapeloperator
      auto func = it->second;
      func(stapel);                        // … wende func auf Stapel an
    } else {
      std::cout << "\n'" << c << "' verstehe ich nicht.\n";
    }
  } /* for c */
}
int main(int argc, const char* argv[]) {
    if(argc > 1) {
        rechner(argv[1]);
    } else {
        // 3+4*5+6 mit Punkt- vor Strichrechnung ergibt 29
        rechner("345*+6+=");
    }
    rechner("93-=");                     // 9 – 3 = Ausgabe: 6
    rechner("82/=");                     // 8 / 2 = Ausgabe: 4
    rechner("92%=");                     // 9 % 2 = Ausgabe: 1
}

GodboltId:e6xT638ch

Book listing lst-0978-book.cpp:

// https://godbolt.org/z/e6xT638ch 
#include <functional> // substract, minus, bind
#include <iostream>
using std::cout;
int substract(int a, int b) { return a - b; }
int main() {
    using namespace std::placeholders;
    cout << substract(9, 3) << '\n';  // Ausgabe: 6
    auto minus3 = std::bind(substract, _1, 3);
    cout << minus3(9) << '\n';        // Ausgabe: 6
    auto von9 = std::bind(substract, 9, _1);
    cout << von9(3) << '\n';          // Ausgabe: 6
    auto nochmalMinus3 = std::bind(std::minus<int>{}, _1, 3);
    cout << nochmalMinus3(9) << '\n'; // Ausgabe: 6
}

Godbolt Listing lst-0978-godb.cpp, https://godbolt.org/z/e6xT638ch:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/e6xT638ch 
#include <functional> // substract, minus, bind
#include <iostream>
using std::cout;
int substract(int a, int b) { return a - b; }
int main() {
    using namespace std::placeholders;
    cout << substract(9, 3) << '\n';  // Ausgabe: 6
    auto minus3 = std::bind(substract, _1, 3);
    cout << minus3(9) << '\n';        // Ausgabe: 6
    auto von9 = std::bind(substract, 9, _1);
    cout << von9(3) << '\n';          // Ausgabe: 6
    auto nochmalMinus3 = std::bind(std::minus<int>{}, _1, 3);
    cout << nochmalMinus3(9) << '\n'; // Ausgabe: 6
}

Listing 28.44: Mit »bind« können Sie auch alle Parameter einer Funktion festlegen.

Book listing lst-0979-book.cpp:

// https://godbolt.org/z/xxfbGd9Ma 
#include <random>
#include <vector>
#include <iostream>
#include <functional>
void wuerfel() {
  std::default_random_engine engine{};
  std::vector<size_t> counts{0,0,0,0,0,0};
  std::uniform_int_distribution<int> w6{0, 5}; // gleichverteilte Ganzzahlen
  auto w = std::bind(w6, engine);              // w() = w6(engine)
  for(auto i=1200*1000; i>0; --i) ++counts[w()];
  for(auto c : counts) std::cout<<" "<<c;
  std::cout << '\n';
}
int main() {
    wuerfel();
}

Godbolt Listing lst-0979-godb.cpp, https://godbolt.org/z/xxfbGd9Ma:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xxfbGd9Ma 
#include <random>
#include <vector>
#include <iostream>
#include <functional>
void wuerfel() {
  std::default_random_engine engine{};
  std::vector<size_t> counts{0,0,0,0,0,0};
  std::uniform_int_distribution<int> w6{0, 5}; // gleichverteilte Ganzzahlen
  auto w = std::bind(w6, engine);              // w() = w6(engine)
  for(auto i=1200*1000; i>0; --i) ++counts[w()];
  for(auto c : counts) std::cout<<" "<<c;
  std::cout << '\n';
}
int main() {
    wuerfel();
}

Listing 28.45: So machen Sie aus Klassenmitgliedern freie Funktionen.

Book listing lst-0982-book.cpp:

// https://godbolt.org/z/a3aTx7K7h 
#include <functional>
#include <iostream>
struct Zahlen {
    int dieZahl() {
        return 42;
    }
    int mehr(int n) {
        return n + data;
    }
    int data = 7;
};
int main() {
    auto func = std::mem_fn(&Zahlen::dieZahl);
    auto func2 = std::mem_fn(&Zahlen::mehr);
    auto zugriff = std::mem_fn(&Zahlen::data);
    Zahlen zahlen;
    std::cout << func(zahlen) << '\n';        // Ausgabe: 42
    std::cout << func2(zahlen, 66) << '\n';   // Ausgabe: 73
    std::cout << zugriff(zahlen) << '\n';     // Ausgabe: 7
}

Godbolt Listing lst-0982-godb.cpp, https://godbolt.org/z/a3aTx7K7h:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/a3aTx7K7h 
#include <functional>
#include <iostream>
struct Zahlen {
    int dieZahl() {
        return 42;
    }
    int mehr(int n) {
        return n + data;
    }
    int data = 7;
};
int main() {
    auto func = std::mem_fn(&Zahlen::dieZahl);
    auto func2 = std::mem_fn(&Zahlen::mehr);
    auto zugriff = std::mem_fn(&Zahlen::data);
    Zahlen zahlen;
    std::cout << func(zahlen) << '\n';        // Ausgabe: 42
    std::cout << func2(zahlen, 66) << '\n';   // Ausgabe: 73
    std::cout << zugriff(zahlen) << '\n';     // Ausgabe: 7
}

Listing 28.46: Basisfunktionalitäten von »variant«

Book listing lst-0983-book.cpp:

// https://godbolt.org/z/P8d494P6c 
#include <variant> 
using std::get;
int main() {
    std::variant<int, float> v{};
    v = 12;                  // Zustand wechselt auf int
    auto i = get<int>(v);    // holt den int
    std::cout << i << '\n';  // Ausgabe: 12
    v = 3.456f;              // Zustand wechselt auf float
    std::cout << get<float>(v) << '\n';  // Ausgabe: 3.456
    get<double>(v);          //             (ERR)  Fehler
    get<3>(v);               //             (ERR)  Fehler
    std::variant<int, float> w{};
    w = get<float>(v);       // Zugriff über Typ
    w = get<1>(v);           // Zugriff geht auch über Index
    w = v;                   // ganze Zuweisung geht auch
    try {
        get<int>(w);         // löst Exception aus
    } catch (std::bad_variant_access&) { /* ... */ }
}

Godbolt Listing lst-0983-godb.cpp, https://godbolt.org/z/P8d494P6c:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/P8d494P6c 
#include <variant> 
using std::get;
int main() {
    std::variant<int, float> v{};
    v = 12;                  // Zustand wechselt auf int
    auto i = get<int>(v);    // holt den int
    std::cout << i << '\n';  // Ausgabe: 12
    v = 3.456f;              // Zustand wechselt auf float
    std::cout << get<float>(v) << '\n';  // Ausgabe: 3.456
    get<double>(v);          //             (ERR)  Fehler
    get<3>(v);               //             (ERR)  Fehler
    std::variant<int, float> w{};
    w = get<float>(v);       // Zugriff über Typ
    w = get<1>(v);           // Zugriff geht auch über Index
    w = v;                   // ganze Zuweisung geht auch
    try {
        get<int>(w);         // löst Exception aus
    } catch (std::bad_variant_access&) { /* ... */ }
}

Listing 28.47: Einen »variant« per Visitor inspizieren

Book listing lst-0984-book.cpp:

// https://godbolt.org/z/ce3jETW6W 
#include <variant>
#include <iostream>
using std::cout;
struct TypGruss {
  void operator()(int) const { cout << "Hallo int"; }
  void operator()(float) const { cout << "Servus float"; }
};
int main() {
    std::variant<int, float> var{};
    var = 12;                                   // Zustand int
    std::visit([](auto a) { cout << a; }, var); // generisches Lambda
    cout << std::endl;
    var = 3.456f;                               // Zustand float
    std::visit(TypGruss{}, var);                // Funktor mit Überladungen
    cout << std::endl;
}

Godbolt Listing lst-0984-godb.cpp, https://godbolt.org/z/ce3jETW6W:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ce3jETW6W 
#include <variant>
#include <iostream>
using std::cout;
struct TypGruss {
  void operator()(int) const { cout << "Hallo int"; }
  void operator()(float) const { cout << "Servus float"; }
};
int main() {
    std::variant<int, float> var{};
    var = 12;                                   // Zustand int
    std::visit([](auto a) { cout << a; }, var); // generisches Lambda
    cout << std::endl;
    var = 3.456f;                               // Zustand float
    std::visit(TypGruss{}, var);                // Funktor mit Überladungen
    cout << std::endl;
}

GodboltId:1eco9Wcr3

Book listing lst-0985-book.cpp:

// https://godbolt.org/z/1eco9Wcr3 
#include <any>
#include <iostream>
#include <vector>
#include <string>
int main() {
    std::any a = 5;
    std::cout << std::any_cast<int>(a) << '\n';
    a = 3.456;
    std::cout << std::any_cast<double>(a) << '\n';
    using namespace std::literals;
    std::vector<std::any> data { 4, 8.976, "Geronimo"s };
    std::cout << std::any_cast<double>( data[1] ) << '\n';
    std::cout << data[1].type().name()  << '\n';
}

Godbolt Listing lst-0985-godb.cpp, https://godbolt.org/z/1eco9Wcr3:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1eco9Wcr3 
#include <any>
#include <iostream>
#include <vector>
#include <string>
int main() {
    std::any a = 5;
    std::cout << std::any_cast<int>(a) << '\n';
    a = 3.456;
    std::cout << std::any_cast<double>(a) << '\n';
    using namespace std::literals;
    std::vector<std::any> data { 4, 8.976, "Geronimo"s };
    std::cout << std::any_cast<double>( data[1] ) << '\n';
    std::cout << data[1].type().name()  << '\n';
}

GodboltId:r5PqK8M8o

Book listing lst-0988-book.cpp:

// https://godbolt.org/z/r5PqK8M8o 
#include <charconv>
#include <vector>
#include <iostream>
#include <string>

std::vector<size_t> num_to_vec(const std::string& nums) {
    std::vector<size_t> result {};
    // ohne Leerzeichen am Ende
    const auto end = nums.data() + nums.find_last_not_of( ' ' ) + 1;
    const char* st = nullptr; // Zählpointer in der Schleife
    auto last = nums.data();  // letztes nicht übersetztes Zeichen
    size_t n;                 // konvertierte Zahl
    do {
        for(st = last; (st<end)&&(*st==' ' ); ++st); // überspringe ' '
        if (last = std::from_chars(st, end, n).ptr; last != st)
            result.push_back(n);                     // speichere Zahl
    } while (last != st);
    return result;
}

void fehlerDemo(const char* buf, size_t sz) {
    int n;
    auto [p, ec] = std::from_chars(buf, buf+sz, n);
    if (ec != std::errc{}) {
       const auto error = std::make_error_code(ec);
       std::cout << error.message() << '\n';
    }
}

int main() {
    auto result = num_to_vec("12 33 43");

    for(auto r : result) std::cout << r << " ";
    std::cout << '\n';
    // Ausgabe: 12 33 43

    fehlerDemo("XYZ", 4);
    // Ausgabe: Invalid argument

    fehlerDemo("123123123123123", 16);
    // Ausgabe: Numerical result out of range
}

Godbolt Listing lst-0988-godb.cpp, https://godbolt.org/z/r5PqK8M8o:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/r5PqK8M8o 
#include <charconv>
#include <vector>
#include <iostream>
#include <string>

std::vector<size_t> num_to_vec(const std::string& nums) {
    std::vector<size_t> result {};
    // ohne Leerzeichen am Ende
    const auto end = nums.data() + nums.find_last_not_of( ' ' ) + 1;
    const char* st = nullptr; // Zählpointer in der Schleife
    auto last = nums.data();  // letztes nicht übersetztes Zeichen
    size_t n;                 // konvertierte Zahl
    do {
        for(st = last; (st<end)&&(*st==' ' ); ++st); // überspringe ' '
        if (last = std::from_chars(st, end, n).ptr; last != st)
            result.push_back(n);                     // speichere Zahl
    } while (last != st);
    return result;
}

void fehlerDemo(const char* buf, size_t sz) {
    int n;
    auto [p, ec] = std::from_chars(buf, buf+sz, n);
    if (ec != std::errc{}) {
       const auto error = std::make_error_code(ec);
       std::cout << error.message() << '\n';
    }
}

int main() {
    auto result = num_to_vec("12 33 43");

    for(auto r : result) std::cout << r << " ";
    std::cout << '\n';
    // Ausgabe: 12 33 43

    fehlerDemo("XYZ", 4);
    // Ausgabe: Invalid argument

    fehlerDemo("123123123123123", 16);
    // Ausgabe: Numerical result out of range
}

GodboltId:dcqenEd31

Book listing lst-0990-book.cpp:

// https://godbolt.org/z/dcqenEd31 
#include <iostream>
#include <charconv>
#include <string_view>
#include <array>
int main() {
    std::array<char, 10> str {};
    if(auto [p, ec] = std::to_chars(str.data(), str.data() + str.size(), 42);
       ec == std::errc{} )
        std::cout << std::string_view(str.data(), p - str.data()) << "\n";
}

Godbolt Listing lst-0990-godb.cpp, https://godbolt.org/z/dcqenEd31:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/dcqenEd31 
#include <iostream>
#include <charconv>
#include <string_view>
#include <array>
int main() {
    std::array<char, 10> str {};
    if(auto [p, ec] = std::to_chars(str.data(), str.data() + str.size(), 42);
       ec == std::errc{} )
        std::cout << std::string_view(str.data(), p - str.data()) << "\n";
}

Listing 29.1: So starten Sie einen Thread.

Book listing lst-0991-book.cpp:

// https://godbolt.org/z/qnadYPWh1 
#include <iostream>
#include <thread>
using std::cout; using std::endl;

long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void aufgabe1() { auto r = fib(40); cout << "fib(40)=" << r << endl; }
void aufgabe2() { auto r = fib(41); cout << "fib(41)=" << r << endl; }
void aufgabe3() { auto r = fib(42); cout << "fib(42)=" << r << endl; }

struct HintergrundAufgabe {
    void operator()() const {
        aufgabe1();
        aufgabe2();
        aufgabe3();
    }
};

int main() {
    HintergrundAufgabe hintergrundAufgabe{};  // Initialisierung, berechnet noch nichts
    std::jthread meinThread{ hintergrundAufgabe }; // Berechnung startet
}

Godbolt Listing lst-0991-godb.cpp, https://godbolt.org/z/qnadYPWh1:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/qnadYPWh1 
#include <iostream>
#include <thread>
using std::cout; using std::endl;

long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void aufgabe1() { auto r = fib(40); cout << "fib(40)=" << r << endl; }
void aufgabe2() { auto r = fib(41); cout << "fib(41)=" << r << endl; }
void aufgabe3() { auto r = fib(42); cout << "fib(42)=" << r << endl; }

struct HintergrundAufgabe {
    void operator()() const {
        aufgabe1();
        aufgabe2();
        aufgabe3();
    }
};

int main() {
    HintergrundAufgabe hintergrundAufgabe{};  // Initialisierung, berechnet noch nichts
    std::jthread meinThread{ hintergrundAufgabe }; // Berechnung startet
}

GodboltId:nPGY47r4K

Book listing lst-0993-book.cpp:

// https://godbolt.org/z/nPGY47r4K 
std::jthread meinThread{ [] {
    aufgabe1();
    aufgabe2();
    aufgabe3();
} };

Godbolt Listing lst-0993-godb.cpp, https://godbolt.org/z/nPGY47r4K:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/nPGY47r4K 
std::jthread meinThread{ [] {
    aufgabe1();
    aufgabe2();
    aufgabe3();
} };

Listing 29.2: Mit »stop_token« kommuniziert die Außenwelt in den Thread hinein.

Book listing lst-0994-book.cpp:

// https://godbolt.org/z/6cqd7Tsae 
struct HintergrundAufgabe {
    void operator()(std::stop_token st) const { // Token fürs Kommunizieren
        aufgabe1();
        if(st.stop_requested()) return;
        aufgabe2();
        if(st.stop_requested()) return;
        aufgabe3();
    }
};
int main() {
    HintergrundAufgabe hintergrundAufgabe{};
    std::jthread meinThread{ hintergrundAufgabe };
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); // warte 100ms
    meinThread.request_stop(); // bitte den Thread, sich zu beenden
}

Godbolt Listing lst-0994-godb.cpp, https://godbolt.org/z/6cqd7Tsae:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/6cqd7Tsae 
struct HintergrundAufgabe {
    void operator()(std::stop_token st) const { // Token fürs Kommunizieren
        aufgabe1();
        if(st.stop_requested()) return;
        aufgabe2();
        if(st.stop_requested()) return;
        aufgabe3();
    }
};
int main() {
    HintergrundAufgabe hintergrundAufgabe{};
    std::jthread meinThread{ hintergrundAufgabe };
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); // warte 100ms
    meinThread.request_stop(); // bitte den Thread, sich zu beenden
}

GodboltId:Tzs93MzfK

Book listing lst-0995-book.cpp:

// https://godbolt.org/z/Tzs93MzfK 
std::thread meinThread{ [] {  // purer Thread
    aufgabe1();
    aufgabe2();
    aufgabe3();
} };
meinThread.join();   // wartet auf das Ende des Threads

Godbolt Listing lst-0995-godb.cpp, https://godbolt.org/z/Tzs93MzfK:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Tzs93MzfK 
std::thread meinThread{ [] {  // purer Thread
    aufgabe1();
    aufgabe2();
    aufgabe3();
} };
meinThread.join();   // wartet auf das Ende des Threads

GodboltId:1jhrx1MMn

Book listing lst-0996-book.cpp:

// https://godbolt.org/z/1jhrx1MMn 
#include <iostream>
#include <thread>
#include <vector>
#include <exception>
using std::cout; using std::endl;

long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void aufgabe1() { auto r = fib(40); cout << "fib(40)=" << r << endl; }

void hauptprogramm() {
    try {
        std::thread th{ &aufgabe1 };
        std::vector data{ 0,1,2 };
        data.at(666);                     //             (ERR)  löst out_of_range aus
        th.join();                        // würde warten
    } catch(std::runtime_error &ex) {           //             (ERR)  passt nicht auf out_of_range
         /*...*/
    }
}

int main() {
  try {
    hauptprogramm();
  } catch( ... ) {                               // so weit, so gut, sieht sicher aus
    std::cout << "Ein Fehler ist aufgetreten\n"; // bekommen Sie nicht zu Gesicht
  }
}

Godbolt Listing lst-0996-godb.cpp, https://godbolt.org/z/1jhrx1MMn:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1jhrx1MMn 
#include <iostream>
#include <thread>
#include <vector>
#include <exception>
using std::cout; using std::endl;

long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void aufgabe1() { auto r = fib(40); cout << "fib(40)=" << r << endl; }

void hauptprogramm() {
    try {
        std::thread th{ &aufgabe1 };
        std::vector data{ 0,1,2 };
        data.at(666);                     //             (ERR)  löst out_of_range aus
        th.join();                        // würde warten
    } catch(std::runtime_error &ex) {           //             (ERR)  passt nicht auf out_of_range
         /*...*/
    }
}

int main() {
  try {
    hauptprogramm();
  } catch( ... ) {                               // so weit, so gut, sieht sicher aus
    std::cout << "Ein Fehler ist aufgetreten\n"; // bekommen Sie nicht zu Gesicht
  }
}

GodboltId:1aj16d7Ga

Book listing lst-0997-book.cpp:

// https://godbolt.org/z/1aj16d7Ga 
#include <iostream>
#include <thread>
#include <vector>
#include <exception>
using std::cout; using std::endl;

long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void aufgabe1() { auto r = fib(40); cout << "fib(40)=" << r << endl; }

void hauptprogramm() {
    std::thread th{ &aufgabe1 };
    try {
        std::vector data{ 0,1,2 };
        data.at(666);                 //             (ERR)  löst out_of_range aus
    } catch(std::runtime_error &ex) { // passt nicht auf out_of_range
         /* ... */                        // speziellen Fehler hier behandeln
    } catch( ... ) {
        th.join();
        throw;                        // Fehlerbehandlung außen fortsetzen
    }
    th.join();                        // wartet nach Okay oder speziellem Fehler
}

int main() {
    try {
        hauptprogramm();
    } catch( ... ) {
        std::cout << "Ein Fehler ist aufgetreten\n";
    }
}

Godbolt Listing lst-0997-godb.cpp, https://godbolt.org/z/1aj16d7Ga:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1aj16d7Ga 
#include <iostream>
#include <thread>
#include <vector>
#include <exception>
using std::cout; using std::endl;

long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void aufgabe1() { auto r = fib(40); cout << "fib(40)=" << r << endl; }

void hauptprogramm() {
    std::thread th{ &aufgabe1 };
    try {
        std::vector data{ 0,1,2 };
        data.at(666);                 //             (ERR)  löst out_of_range aus
    } catch(std::runtime_error &ex) { // passt nicht auf out_of_range
         /* ... */                        // speziellen Fehler hier behandeln
    } catch( ... ) {
        th.join();
        throw;                        // Fehlerbehandlung außen fortsetzen
    }
    th.join();                        // wartet nach Okay oder speziellem Fehler
}

int main() {
    try {
        hauptprogramm();
    } catch( ... ) {
        std::cout << "Ein Fehler ist aufgetreten\n";
    }
}

GodboltId:8TdzEGf3d

Book listing lst-0998-book.cpp:

// https://godbolt.org/z/8TdzEGf3d 
void hauptprogramm() {
    std::jthread th{ &aufgabe1 };
    std::vector data{ 0,1,2 };
    data.at(666);                 //             (ERR)  löst out_of_range aus
}

Godbolt Listing lst-0998-godb.cpp, https://godbolt.org/z/8TdzEGf3d:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/8TdzEGf3d 
void hauptprogramm() {
    std::jthread th{ &aufgabe1 };
    std::vector data{ 0,1,2 };
    data.at(666);                 //             (ERR)  löst out_of_range aus
}

Listing 29.3: Parameter an die Threadfunktion fügen Sie dem Konstruktor hinzu.

Book listing lst-0999-book.cpp:

// https://godbolt.org/z/PP4GT3oc6 
#include <iostream>
#include <thread>
using std::cout; using std::endl;

long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void runFib(long n) {
    auto r = fib(n);
    cout << "fib("<<n<<")=" << r << endl;
}
long ack(long m, long n) { // Ackermannfunktion
    if(m==0) return n+1;
    if(n==0) return ack(m-1, 1);
    return ack(m - 1, ack(m, n-1));
}
void runAck(long m, long n) {
    auto r = ack(m, n);
    cout << "ack("<<m<<','<<n<<")=" << r << endl;
}

int main() {
    std::jthread f40{ runFib, 40 };
    std::jthread f41{ runFib, 41 };
    std::jthread f42{ runFib, 42 };

    f40.join(); f41.join(); f42.join();

    std::thread a1{ runAck, 4, 0 };
    std::thread a2{ runAck, 4, 1 };
    std::thread a3{ runAck, 2, 700 };
    std::thread a4{ runAck, 3, 10 };
}

Godbolt Listing lst-0999-godb.cpp, https://godbolt.org/z/PP4GT3oc6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/PP4GT3oc6 
#include <iostream>
#include <thread>
using std::cout; using std::endl;

long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void runFib(long n) {
    auto r = fib(n);
    cout << "fib("<<n<<")=" << r << endl;
}
long ack(long m, long n) { // Ackermannfunktion
    if(m==0) return n+1;
    if(n==0) return ack(m-1, 1);
    return ack(m - 1, ack(m, n-1));
}
void runAck(long m, long n) {
    auto r = ack(m, n);
    cout << "ack("<<m<<','<<n<<")=" << r << endl;
}

int main() {
    std::jthread f40{ runFib, 40 };
    std::jthread f41{ runFib, 41 };
    std::jthread f42{ runFib, 42 };

    f40.join(); f41.join(); f42.join();

    std::thread a1{ runAck, 4, 0 };
    std::thread a2{ runAck, 4, 1 };
    std::thread a3{ runAck, 2, 700 };
    std::thread a4{ runAck, 3, 10 };
}

Listing 29.4: Parameter werden in den Thread kopiert.

Book listing lst-1000-book.cpp:

// https://godbolt.org/z/fbnbKzrs1 
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s

void delayPrint(seconds s, const std::string& msg) {
    std::this_thread::sleep_for(s);
    std::cout << msg << std::endl;
}
int main() {
    std::jthread m1{ delayPrint, 1s, "Auf die Plaetze" };
    std::jthread m2{ delayPrint, 2s, std::string{"fertig"} };
    std::string los = "los";
    std::jthread m3{ delayPrint, 3s, los };
}

Godbolt Listing lst-1000-godb.cpp, https://godbolt.org/z/fbnbKzrs1:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/fbnbKzrs1 
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s

void delayPrint(seconds s, const std::string& msg) {
    std::this_thread::sleep_for(s);
    std::cout << msg << std::endl;
}
int main() {
    std::jthread m1{ delayPrint, 1s, "Auf die Plaetze" };
    std::jthread m2{ delayPrint, 2s, std::string{"fertig"} };
    std::string los = "los";
    std::jthread m3{ delayPrint, 3s, los };
}

Listing 29.5: Achtung mit rohen Zeigern als Parameter

Book listing lst-1001-book.cpp:

// https://godbolt.org/z/hvq5dbzde 
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s

void delayPrint(seconds s, const char* msg) { //                     (ERR)  roher Zeiger
    std::this_thread::sleep_for(s);
    std::cout << msg << std::endl;            //                     (ERR)  das klappt nicht
}

void lauf() {
    const char risiko[] = "Das geht nicht gut...";
    std::jthread m{ delayPrint, 1s, risiko }; //                     (ERR)  roher Zeiger
    m.detach();
    // hier wird der Bereich von 'risiko' verlassen
}
int main() {
    lauf();
    std::this_thread::sleep_for(2s);          // noch 2 Sekunden warten
}

Godbolt Listing lst-1001-godb.cpp, https://godbolt.org/z/hvq5dbzde:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/hvq5dbzde 
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s

void delayPrint(seconds s, const char* msg) { //                     (ERR)  roher Zeiger
    std::this_thread::sleep_for(s);
    std::cout << msg << std::endl;            //                     (ERR)  das klappt nicht
}

void lauf() {
    const char risiko[] = "Das geht nicht gut...";
    std::jthread m{ delayPrint, 1s, risiko }; //                     (ERR)  roher Zeiger
    m.detach();
    // hier wird der Bereich von 'risiko' verlassen
}
int main() {
    lauf();
    std::this_thread::sleep_for(2s);          // noch 2 Sekunden warten
}

Listing 29.6: Mit ref eine Referenz erzwingen

Book listing lst-1002-book.cpp:

// https://godbolt.org/z/GnsWYvecv 
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
struct Zustand {
    int zaehler;
};
void zeigeZustand(const Zustand& zustand) {
    for(auto i : { 5,4,3,2,1 }) {
        std::cout << "zaehler: " << zustand.zaehler << std::endl;
        std::this_thread::sleep_for(1s);
    }
}
int main() {
    Zustand zustand { 4 };
    std::jthread th{zeigeZustand, std::ref(zustand)}; // bleibt Referenz auf zustand
    std::this_thread::sleep_for(1s);
    zustand.zaehler = 501;
    std::this_thread::sleep_for(1s);
    zustand.zaehler = 87;
    std::this_thread::sleep_for(1s);
    zustand.zaehler = 2;
}

Godbolt Listing lst-1002-godb.cpp, https://godbolt.org/z/GnsWYvecv:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/GnsWYvecv 
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
struct Zustand {
    int zaehler;
};
void zeigeZustand(const Zustand& zustand) {
    for(auto i : { 5,4,3,2,1 }) {
        std::cout << "zaehler: " << zustand.zaehler << std::endl;
        std::this_thread::sleep_for(1s);
    }
}
int main() {
    Zustand zustand { 4 };
    std::jthread th{zeigeZustand, std::ref(zustand)}; // bleibt Referenz auf zustand
    std::this_thread::sleep_for(1s);
    zustand.zaehler = 501;
    std::this_thread::sleep_for(1s);
    zustand.zaehler = 87;
    std::this_thread::sleep_for(1s);
    zustand.zaehler = 2;
}

Listing 29.7: Mit move Eingaben in den Thread verschieben

Book listing lst-1003-book.cpp:

// https://godbolt.org/z/j5Y15Esx7 
// … includes …
#include <thread>
using namespace std::chrono; // seconds, suffix s
struct Image {
    std::vector<char> data_; // Kopie teuer
    explicit Image() : data_(1'000'000) {}
};
void zeigeImage(Image img) {
    std::cout << img.data_.size() << '\n';
}
void zeigeIptr(std::unique_ptr<int> iptr) {
    std::cout << *iptr << '\n';
}
int main() {
    // teuer zu kopieren, aber dafür gut zu verschieben:
    Image image{};
    std::cout << image.data_.size() << std::endl;    // Ausgabe: 1000000
    std::jthread th1{ zeigeImage, std::move(image) };// Ausgabe: 1000000
    std::this_thread::sleep_for(1s);
    std::cout << image.data_.size() << std::endl;    // Ausgabe: 0
    th1.join();  // explizit warten, bis der Thread fertig ist
    // unmöglich zu kopieren, aber gut zu verschieben:
    auto iptr = std::make_unique<int>( 657 );
    std::cout << (bool)iptr << std::endl;            // Ausgabe: 1 für wahr
    std::jthread th2{ zeigeIptr, std::move(iptr) };  // Ausgabe: 657
    std::this_thread::sleep_for(1s);
    std::cout << (bool)iptr.get() << std::endl;      // Ausgabe: 0 für falsch
}

Godbolt Listing lst-1003-godb.cpp, https://godbolt.org/z/j5Y15Esx7:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/j5Y15Esx7 
// … includes …
#include <thread>
using namespace std::chrono; // seconds, suffix s
struct Image {
    std::vector<char> data_; // Kopie teuer
    explicit Image() : data_(1'000'000) {}
};
void zeigeImage(Image img) {
    std::cout << img.data_.size() << '\n';
}
void zeigeIptr(std::unique_ptr<int> iptr) {
    std::cout << *iptr << '\n';
}
int main() {
    // teuer zu kopieren, aber dafür gut zu verschieben:
    Image image{};
    std::cout << image.data_.size() << std::endl;    // Ausgabe: 1000000
    std::jthread th1{ zeigeImage, std::move(image) };// Ausgabe: 1000000
    std::this_thread::sleep_for(1s);
    std::cout << image.data_.size() << std::endl;    // Ausgabe: 0
    th1.join();  // explizit warten, bis der Thread fertig ist
    // unmöglich zu kopieren, aber gut zu verschieben:
    auto iptr = std::make_unique<int>( 657 );
    std::cout << (bool)iptr << std::endl;            // Ausgabe: 1 für wahr
    std::jthread th2{ zeigeIptr, std::move(iptr) };  // Ausgabe: 657
    std::this_thread::sleep_for(1s);
    std::cout << (bool)iptr.get() << std::endl;      // Ausgabe: 0 für falsch
}

Listing 29.8: Einen Thread zurückgeben

Book listing lst-1004-book.cpp:

// https://godbolt.org/z/Kv84eb96E 
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
auto makeThread(std::string wer) {
    return std::jthread{ [wer] {
        std::this_thread::sleep_for(1s);
        std::cout << "Viel Glueck, " << wer << std::endl;
    } };
}
int main() {
    auto th = makeThread("Jim"); // Ausgabe: Viel Glueck, Jim
    th.join();
}

Godbolt Listing lst-1004-godb.cpp, https://godbolt.org/z/Kv84eb96E:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Kv84eb96E 
#include <iostream>
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
auto makeThread(std::string wer) {
    return std::jthread{ [wer] {
        std::this_thread::sleep_for(1s);
        std::cout << "Viel Glueck, " << wer << std::endl;
    } };
}
int main() {
    auto th = makeThread("Jim"); // Ausgabe: Viel Glueck, Jim
    th.join();
}

Listing 29.9: Einen Thread verschieben

Book listing lst-1005-book.cpp:

// https://godbolt.org/z/39x4bafco 
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
void kobraUebernehmenSie(std::jthread job) {
    job.join();
}
int main() {
     std::jthread th{ [] {
        std::this_thread::sleep_for(1s);
        std::cout << "Viel Glueck, Dan" << std::endl;
    } };
    kobraUebernehmenSie( std::move(th) );  // Zuständigkeit übertragen
}

Godbolt Listing lst-1005-godb.cpp, https://godbolt.org/z/39x4bafco:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/39x4bafco 
#include <thread>
#include <chrono>
using namespace std::chrono; // seconds, suffix s
void kobraUebernehmenSie(std::jthread job) {
    job.join();
}
int main() {
     std::jthread th{ [] {
        std::this_thread::sleep_for(1s);
        std::cout << "Viel Glueck, Dan" << std::endl;
    } };
    kobraUebernehmenSie( std::move(th) );  // Zuständigkeit übertragen
}

Listing 29.10: Threads im Container

Book listing lst-1006-book.cpp:

// https://godbolt.org/z/YrEPnYMaP 
#include <iostream>
#include <thread>
#include <vector>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void runFib(long n) { auto r = fib(n); cout << "fib("<<n<<")=" << r << endl; }
int main() {
    std::vector<std::jthread> threads;
    // starten
    for( auto n : { 38, 39, 40, 41, 42, 43, }) {
        threads.emplace_back( runFib, n );
    }
}

Godbolt Listing lst-1006-godb.cpp, https://godbolt.org/z/YrEPnYMaP:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/YrEPnYMaP 
#include <iostream>
#include <thread>
#include <vector>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
void runFib(long n) { auto r = fib(n); cout << "fib("<<n<<")=" << r << endl; }
int main() {
    std::vector<std::jthread> threads;
    // starten
    for( auto n : { 38, 39, 40, 41, 42, 43, }) {
        threads.emplace_back( runFib, n );
    }
}

Listing 29.11: Parallelität der Hardware herausfinden

Book listing lst-1009-book.cpp:

// https://godbolt.org/z/Gen1rfEn6 
#include <thread>
#include <iostream>
#include <vector>
#include <chrono>  // steady_clock
using std::cout; using std::endl; using namespace std::chrono;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }

int main() {
  cout << std::thread::hardware_concurrency() << '\n';
  for(int nthreads : { 1,2,3,4,5,6 }) {
    cout << "Threads: ";
    const auto start = steady_clock::now();

    std::vector<std::jthread> threads;
    for(int ti = 1; ti <= nthreads; ++ti) {
      threads.emplace_back( std::jthread{fib, 40});
      cout << ti << "... "; cout.flush();
    }
    for(auto &th : threads) th.join(); // explizit joinen vor der Zeitmessung

    const auto now = steady_clock::now();
    cout << "  Zeit:  " << duration_cast<milliseconds>(
        now-start).count()<<"ms\n";
  }
}

Godbolt Listing lst-1009-godb.cpp, https://godbolt.org/z/Gen1rfEn6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Gen1rfEn6 
#include <thread>
#include <iostream>
#include <vector>
#include <chrono>  // steady_clock
using std::cout; using std::endl; using namespace std::chrono;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }

int main() {
  cout << std::thread::hardware_concurrency() << '\n';
  for(int nthreads : { 1,2,3,4,5,6 }) {
    cout << "Threads: ";
    const auto start = steady_clock::now();

    std::vector<std::jthread> threads;
    for(int ti = 1; ti <= nthreads; ++ti) {
      threads.emplace_back( std::jthread{fib, 40});
      cout << ti << "... "; cout.flush();
    }
    for(auto &th : threads) th.join(); // explizit joinen vor der Zeitmessung

    const auto now = steady_clock::now();
    cout << "  Zeit:  " << duration_cast<milliseconds>(
        now-start).count()<<"ms\n";
  }
}

Listing 29.12: Jeder Thread hat eine Kennung.

Book listing lst-1010-book.cpp:

// https://godbolt.org/z/TM6c7cdss 
#include <thread>
#include <iostream>
int main() {
    std::cout << "Main: " << std::this_thread::get_id() << '\n';
    std::jthread th{ []{
        std::cout << "Thread: " << std::this_thread::get_id() << '\n';
    }};
}

Godbolt Listing lst-1010-godb.cpp, https://godbolt.org/z/TM6c7cdss:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TM6c7cdss 
#include <thread>
#include <iostream>
int main() {
    std::cout << "Main: " << std::this_thread::get_id() << '\n';
    std::jthread th{ []{
        std::cout << "Thread: " << std::this_thread::get_id() << '\n';
    }};
}

Listing 29.13: Ein klassisches Data Race

Book listing lst-1011-book.cpp:

// https://godbolt.org/z/7GEs9a4n6 
#include <thread>
#include <iostream>

int count = 0; // wird simultan verändert

void run() {
    for(int i=0; i<1'000'000; ++i) {
        count += 1;   // ungeschützt
    }
}

int main() {
    std::cout << "Start: " << count << '\n';  // Ausgabe: Start: 0
    std::thread th1{ run };
    std::thread th2{ run };
    std::thread th3{ run };
    th1.join(); th2.join(); th3.join();
    std::cout << "Ende: " << count << '\n';  // Ausgabe sicher nicht: 3000000
}

Godbolt Listing lst-1011-godb.cpp, https://godbolt.org/z/7GEs9a4n6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7GEs9a4n6 
#include <thread>
#include <iostream>

int count = 0; // wird simultan verändert

void run() {
    for(int i=0; i<1'000'000; ++i) {
        count += 1;   // ungeschützt
    }
}

int main() {
    std::cout << "Start: " << count << '\n';  // Ausgabe: Start: 0
    std::thread th1{ run };
    std::thread th2{ run };
    std::thread th3{ run };
    th1.join(); th2.join(); th3.join();
    std::cout << "Ende: " << count << '\n';  // Ausgabe sicher nicht: 3000000
}

Listing 29.14: Gutartige Data Races sind auch undefiniert.

Book listing lst-1012-book.cpp:

// https://godbolt.org/z/v3b6sxEab 
#include <thread>
/* exakte Zählung nicht so wichtig */
int count = 0; // wird simultan verändert
void run() {
    for(int i=0; i<1'000; ++i) {
        count += 1; // ungeschützt
        if(count > 1000) return;  //                 (ERR)  Endbedingung
        for(int j=0; j<1'000; ++j)
            ;
    }
}

int main() {
    std::thread th1{ run };
    std::thread th2{ run };
    std::thread th3{ run };
    th1.join(); th2.join(); th3.join();
}

Godbolt Listing lst-1012-godb.cpp, https://godbolt.org/z/v3b6sxEab:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/v3b6sxEab 
#include <thread>
/* exakte Zählung nicht so wichtig */
int count = 0; // wird simultan verändert
void run() {
    for(int i=0; i<1'000; ++i) {
        count += 1; // ungeschützt
        if(count > 1000) return;  //                 (ERR)  Endbedingung
        for(int j=0; j<1'000; ++j)
            ;
    }
}

int main() {
    std::thread th1{ run };
    std::thread th2{ run };
    std::thread th3{ run };
    th1.join(); th2.join(); th3.join();
}

Listing 29.15: Latches können herunterzählen und warten.

Book listing lst-1013-book.cpp:

// https://godbolt.org/z/rrfn4d5WP 
#include <thread>
#include <latch>
#include <iostream>
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }

int main() {
    std::latch la{ 3 };                                // wir erwarten 3 Threads
    std::jthread th1{ [&la] { fib(39); la.count_down(); } };
    std::jthread th2{ [&la] { fib(38); la.count_down(); } };
    std::jthread th3{ [&la] { fib(40); la.count_down(); } };
    fib(37); // Hauptthread
    std::cout << "Haupthread: fertig\n";
    la.wait();                                         // wartet bis la == 0
    std::cout << "Rest fertig\n";
}

Godbolt Listing lst-1013-godb.cpp, https://godbolt.org/z/rrfn4d5WP:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/rrfn4d5WP 
#include <thread>
#include <latch>
#include <iostream>
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }

int main() {
    std::latch la{ 3 };                                // wir erwarten 3 Threads
    std::jthread th1{ [&la] { fib(39); la.count_down(); } };
    std::jthread th2{ [&la] { fib(38); la.count_down(); } };
    std::jthread th3{ [&la] { fib(40); la.count_down(); } };
    fib(37); // Hauptthread
    std::cout << "Haupthread: fertig\n";
    la.wait();                                         // wartet bis la == 0
    std::cout << "Rest fertig\n";
}

Listing 29.16: Eine Barriere wartet auf eine bestimmte Anzahl von Threads.

Book listing lst-1014-book.cpp:

// https://godbolt.org/z/d3dc1Tsj8 
#include <thread>
#include <barrier>
#include <iostream>
#include <vector>
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }

constexpr int anz = 8;             // 8 Worker
constexpr int max_n = 32;          // bis 32 berechnen
std::vector<long> ergebnisse(anz); // Puffer: Platz für 8 Ergebnisse

void ausgeben() {                  // Signalisierungsfunktion druckt Puffer
    for (auto n : ergebnisse) std::cout << n << ' ';
    std::cout << '\n';
}

std::barrier ba{anz, ausgeben};    // immer nach 8 ausgeben

void worker(std::stop_token st, int idx) {
    // n = 0, 9, 17, 25, … ; 1, 10, 18, 26, …
    for(int n = idx; n<max_n; n += anz) {
        if(st.stop_requested()) return;
        ergebnisse[idx] = fib(n);  // schreibe Ergebnis in Puffer
        ba.arrive_and_wait();      // warte, bis 8 Threads hier sind
    }
}

int main() {
    std::vector<std::jthread> threads;     // 8 Threads
    for (int idx=0; idx<anz; ++idx) {
        threads.emplace_back(worker, idx); // erzeuge Thread mit Index
    }
    for (auto& t : threads) t.join();      // warte, bis alle fertig sind
}

Godbolt Listing lst-1014-godb.cpp, https://godbolt.org/z/d3dc1Tsj8:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/d3dc1Tsj8 
#include <thread>
#include <barrier>
#include <iostream>
#include <vector>
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }

constexpr int anz = 8;             // 8 Worker
constexpr int max_n = 32;          // bis 32 berechnen
std::vector<long> ergebnisse(anz); // Puffer: Platz für 8 Ergebnisse

void ausgeben() {                  // Signalisierungsfunktion druckt Puffer
    for (auto n : ergebnisse) std::cout << n << ' ';
    std::cout << '\n';
}

std::barrier ba{anz, ausgeben};    // immer nach 8 ausgeben

void worker(std::stop_token st, int idx) {
    // n = 0, 9, 17, 25, … ; 1, 10, 18, 26, …
    for(int n = idx; n<max_n; n += anz) {
        if(st.stop_requested()) return;
        ergebnisse[idx] = fib(n);  // schreibe Ergebnis in Puffer
        ba.arrive_and_wait();      // warte, bis 8 Threads hier sind
    }
}

int main() {
    std::vector<std::jthread> threads;     // 8 Threads
    for (int idx=0; idx<anz; ++idx) {
        threads.emplace_back(worker, idx); // erzeuge Thread mit Index
    }
    for (auto& t : threads) t.join();      // warte, bis alle fertig sind
}

Listing 29.17: Ein Mutex zusammen mit einem einfachen Lock

Book listing lst-1015-book.cpp:

// https://godbolt.org/z/3fz5a4vYv 
#include <mutex> // mutex, lock_guard
#include <list>
#include <algorithm> // find
using std::lock_guard; using std::mutex; using std::find;
class MxIntList {
    std::list <int> data_;
    mutable mutex mx_;
public:
    void add(int value) {
        lock_guard guard{mx_};  // schützt bis Ende der Methode
        data_.push_back(value);
    }
    bool contains(int searchVal) const {
        lock_guard guard{mx_};  // schützt bis Ende der Methode
        return find(data_.begin(), data_.end(), searchVal) != data_.end();
    }
};

Godbolt Listing lst-1015-godb.cpp, https://godbolt.org/z/3fz5a4vYv:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3fz5a4vYv 
#include <mutex> // mutex, lock_guard
#include <list>
#include <algorithm> // find
using std::lock_guard; using std::mutex; using std::find;
class MxIntList {
    std::list <int> data_;
    mutable mutex mx_;
public:
    void add(int value) {
        lock_guard guard{mx_};  // schützt bis Ende der Methode
        data_.push_back(value);
    }
    bool contains(int searchVal) const {
        lock_guard guard{mx_};  // schützt bis Ende der Methode
        return find(data_.begin(), data_.end(), searchVal) != data_.end();
    }
};

Listing 29.18: Die Schnittstelle zu einem multithreadfähigen Stack

Book listing lst-1016-book.cpp:

// https://godbolt.org/z/4j7njd763 
#include <vector>

template<class T>
class MxStack {
public:
    bool isEmpty() const;
    void push(const T&);
    void pop();
    const T& top() const;
};

Godbolt Listing lst-1016-godb.cpp, https://godbolt.org/z/4j7njd763:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4j7njd763 
#include <vector>

template<class T>
class MxStack {
public:
    bool isEmpty() const;
    void push(const T&);
    void pop();
    const T& top() const;
};

Listing 29.19: Problematischer Code für den MxStack

Book listing lst-1017-book.cpp:

// https://godbolt.org/z/1boeTMMvf 
MxStack<int> mxs{};
// …
// mehr Code
// …
if( ! mxs.isEmpty()) {            //                 (ERR)  nicht sicher
    const auto value = mxs.top(); //                 (ERR)  nicht sicher
    mxs.pop();                    //                 (ERR)  nicht sicher
    // …
    // mehr Code
    // …
}

Godbolt Listing lst-1017-godb.cpp, https://godbolt.org/z/1boeTMMvf:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1boeTMMvf 
MxStack<int> mxs{};
// …
// mehr Code
// …
if( ! mxs.isEmpty()) {            //                 (ERR)  nicht sicher
    const auto value = mxs.top(); //                 (ERR)  nicht sicher
    mxs.pop();                    //                 (ERR)  nicht sicher
    // …
    // mehr Code
    // …
}

Listing 29.20: Eine Möglichkeit, wie zwei Threads obigen Code ausführen könnten

Book listing lst-1018-book.cpp:

/* Thread 1 */                         /* Thread 2 */
if( ! mxs.isEmpty()) {
                                    if( ! mxs.isEmpty()) {
    const auto value = mxs.top();
                                        const auto value = mxs.top();
    mxs.pop();
    // … mehr Code …
                                        mxs.pop();
                                        // … mehr Code …

Listing 29.21: Ein sehr einfacher threadsicherer Stack

Book listing lst-1019-book.cpp:

// https://godbolt.org/z/xGv9drh73 
#include <vector>
#include <thread>
#include <mutex>
#include <iostream>
#include <numeric>  // iota

/* T: noexcept kopier- und zuweisbar */
template<typename T>
class MxStack {
    std::vector<T> data_;
    std::mutex mx_;

public:
    MxStack() : data_{} {}

    bool isEmpty() const { return data_.empty(); }

    void push(const T& val) {
        std::lock_guard<std::mutex> g{mx_};
        data_.push_back(val);
    }

    T pop() {
        std::lock_guard g{mx_};
        if(data_.empty())
            throw std::length_error{"empty stack"};
        T tmp{std::move(data_.back())};
        data_.pop_back();
        return tmp;
    }
};

int main() {
    // Stack vorbereiten
    MxStack<int> mxs{};
    for(int i=1; i<=1'000'000; ++i) mxs.push(i);
    // Berechnung definieren
    auto sumIt = [&mxs](long &sum) {
        int val{};
        try {
            while( ! mxs.isEmpty()) {
                sum += mxs.pop(); // könnte immer noch werfen
            }
        } catch(std::length_error &ex) {}
    };
    // Berechnen
    long sum1 = 0;          // fürs Teilergebnis
    std::jthread th1{sumIt, std::ref(sum1)};
    long sum2 = 0;          // fürs Teilergebnis
    std::thread th2{sumIt, std::ref(sum2)};
    th1.join(); th2.join();
    long sum = sum1 + sum2; // Gesamtergebnis
    // Ergebnis
    std::cout << "Sollergebnis: "
        << (1'000'000L*1'000'001)/2 << '\n'; // Ausgabe: 500000500000
    std::cout << "Tatsaechlich: "
        << sum << '\n';                      // Ausgabe: 500000500000
}

Godbolt Listing lst-1019-godb.cpp, https://godbolt.org/z/xGv9drh73:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xGv9drh73 
#include <vector>
#include <thread>
#include <mutex>
#include <iostream>
#include <numeric>  // iota

/* T: noexcept kopier- und zuweisbar */
template<typename T>
class MxStack {
    std::vector<T> data_;
    std::mutex mx_;

public:
    MxStack() : data_{} {}

    bool isEmpty() const { return data_.empty(); }

    void push(const T& val) {
        std::lock_guard<std::mutex> g{mx_};
        data_.push_back(val);
    }

    T pop() {
        std::lock_guard g{mx_};
        if(data_.empty())
            throw std::length_error{"empty stack"};
        T tmp{std::move(data_.back())};
        data_.pop_back();
        return tmp;
    }
};

int main() {
    // Stack vorbereiten
    MxStack<int> mxs{};
    for(int i=1; i<=1'000'000; ++i) mxs.push(i);
    // Berechnung definieren
    auto sumIt = [&mxs](long &sum) {
        int val{};
        try {
            while( ! mxs.isEmpty()) {
                sum += mxs.pop(); // könnte immer noch werfen
            }
        } catch(std::length_error &ex) {}
    };
    // Berechnen
    long sum1 = 0;          // fürs Teilergebnis
    std::jthread th1{sumIt, std::ref(sum1)};
    long sum2 = 0;          // fürs Teilergebnis
    std::thread th2{sumIt, std::ref(sum2)};
    th1.join(); th2.join();
    long sum = sum1 + sum2; // Gesamtergebnis
    // Ergebnis
    std::cout << "Sollergebnis: "
        << (1'000'000L*1'000'001)/2 << '\n'; // Ausgabe: 500000500000
    std::cout << "Tatsaechlich: "
        << sum << '\n';                      // Ausgabe: 500000500000
}

Listing 29.22: »swap« für »MxStack«

Book listing lst-1022-book.cpp:

// https://godbolt.org/z/9PMcz1cqP 
friend void swap(MxStack& re, MxStack& li) {
    if(&re==&li) return; // Adresse dieselbe? Mit sich selbst tauschen unnötig
    std::lock( re.mx_, li.mx_ );   // mehrere Sperren gleichzeitig
    std::lock_guard lkre{re.mx_, std::adopt_lock}; // schon gesperrt
    std::lock_guard lkli{li.mx_, std::adopt_lock}; // schon gesperrt
    std::swap(li.data_, re.data_); // vertauschen ausführen
}

Godbolt Listing lst-1022-godb.cpp, https://godbolt.org/z/9PMcz1cqP:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9PMcz1cqP 
friend void swap(MxStack& re, MxStack& li) {
    if(&re==&li) return; // Adresse dieselbe? Mit sich selbst tauschen unnötig
    std::lock( re.mx_, li.mx_ );   // mehrere Sperren gleichzeitig
    std::lock_guard lkre{re.mx_, std::adopt_lock}; // schon gesperrt
    std::lock_guard lkli{li.mx_, std::adopt_lock}; // schon gesperrt
    std::swap(li.data_, re.data_); // vertauschen ausführen
}

Listing 29.23: Mutexe kann man transferieren.

Book listing lst-1023-book.cpp:

// https://godbolt.org/z/e7rraPGx4 
#include <thread>
#include <mutex>
#include <vector>
#include <numeric> // accumulate, iota
using std::mutex; using std::unique_lock;

std::vector<int> myData;             // geteilte Daten
mutex myMutex;                       // Mutex zu den Daten
unique_lock<mutex> bereiteDatenVor() {
    unique_lock lk1{myMutex};        // sperren
    myData.resize(1000);
    std::iota(myData.begin(), myData.end(), 1); // 1..1000
    return lk1;                                 // Sperre transferieren
}
int verarbeiteDaten() {
    unique_lock lk2 = bereiteDatenVor();        // Sperre transferiert
    return std::accumulate(myData.begin(), myData.end(), 0);
}

Godbolt Listing lst-1023-godb.cpp, https://godbolt.org/z/e7rraPGx4:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/e7rraPGx4 
#include <thread>
#include <mutex>
#include <vector>
#include <numeric> // accumulate, iota
using std::mutex; using std::unique_lock;

std::vector<int> myData;             // geteilte Daten
mutex myMutex;                       // Mutex zu den Daten
unique_lock<mutex> bereiteDatenVor() {
    unique_lock lk1{myMutex};        // sperren
    myData.resize(1000);
    std::iota(myData.begin(), myData.end(), 1); // 1..1000
    return lk1;                                 // Sperre transferieren
}
int verarbeiteDaten() {
    unique_lock lk2 = bereiteDatenVor();        // Sperre transferiert
    return std::accumulate(myData.begin(), myData.end(), 0);
}

Listing 29.24: Späte Initialisierung mit nur einem Thread

Book listing lst-1024-book.cpp:

// https://godbolt.org/z/T7vehq58b 
std::shared_ptr<BigData> bigData{};
BigData& getBigData() {
    if(!bigData) bigData.reset(new BigData{});
    return *bigData;
}
int useBigData() {
    auto bigData = getBigData();
    // bigData->…
}

Godbolt Listing lst-1024-godb.cpp, https://godbolt.org/z/T7vehq58b:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/T7vehq58b 
std::shared_ptr<BigData> bigData{};
BigData& getBigData() {
    if(!bigData) bigData.reset(new BigData{});
    return *bigData;
}
int useBigData() {
    auto bigData = getBigData();
    // bigData->…
}

Listing 29.25: Späte Initialisierung mit mehreren Threads

Book listing lst-1025-book.cpp:

// https://godbolt.org/z/3vcnzfqfM 
#include <mutex> // once_flag, call_once
std::shared_ptr<BigData> bigData{};
std::once_flag bigDataInitFlag;
void initBigData() {
    bigData = std::make_shared<BigData>();
}
int useBigData() {
    std::call_once(bigDataInitFlag, initBigData);
    // bigData->…
}

Godbolt Listing lst-1025-godb.cpp, https://godbolt.org/z/3vcnzfqfM:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3vcnzfqfM 
#include <mutex> // once_flag, call_once
std::shared_ptr<BigData> bigData{};
std::once_flag bigDataInitFlag;
void initBigData() {
    bigData = std::make_shared<BigData>();
}
int useBigData() {
    std::call_once(bigDataInitFlag, initBigData);
    // bigData->…
}

Listing 29.26: Späte Initialisierung kann auch innerhalb eines Threads nützlich sein.

Book listing lst-1026-book.cpp:

// https://godbolt.org/z/TcsrefEPh 
#include <mutex> // once_flag, call_once
#include <memory>
struct Connection {
    void csend(const char *data) {} // dummy
    const char* crecv() {} // dummy
};
class Sender {
    std::shared_ptr<Connection> conn_;
    std::once_flag connInitFlag_;
    void open() {
        conn_.reset( new Connection{} );
    }
public:
    void send(const char* data) {
        std::call_once(connInitFlag_, &Sender::open, this); // Methodenzeiger
        conn_->csend(data);
    }
    const char* recv() {
        std::call_once(connInitFlag_, [this] {this->open();} ); // Lambda
        return conn_->crecv();
    }
};

Godbolt Listing lst-1026-godb.cpp, https://godbolt.org/z/TcsrefEPh:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/TcsrefEPh 
#include <mutex> // once_flag, call_once
#include <memory>
struct Connection {
    void csend(const char *data) {} // dummy
    const char* crecv() {} // dummy
};
class Sender {
    std::shared_ptr<Connection> conn_;
    std::once_flag connInitFlag_;
    void open() {
        conn_.reset( new Connection{} );
    }
public:
    void send(const char* data) {
        std::call_once(connInitFlag_, &Sender::open, this); // Methodenzeiger
        conn_->csend(data);
    }
    const char* recv() {
        std::call_once(connInitFlag_, [this] {this->open();} ); // Lambda
        return conn_->crecv();
    }
};

Listing 29.27: Es sind Vorkehrungen nötig, wenn ein Mutex mehrmals gesperrt werden soll.

Book listing lst-1027-book.cpp:

// https://godbolt.org/z/38qMMWoz6 
#include <mutex> // recursive_mutex
#include <iostream>
struct MulDiv {
    std::recursive_mutex mx_;
    int value_;
    explicit MulDiv(int value) : value_{value} {}
    void mul(int x) {
        std::lock_guard lk1(mx_);  // innen
        value_ *= x;
    }
    void div(int x) {
        std::lock_guard lk2(mx_);  // innen
        value_ /= x;
    }
    void muldiv(int x, int y){
        std::lock_guard lk3(mx_);  // außen
        mul(x);
        div(y);
    }
};
int main() {
   MulDiv m{42}; // 3*7*2 *5
   m.muldiv(5, 15);
   std::cout << m.value_ << '\n';  // Ausgabe: 14
}

Godbolt Listing lst-1027-godb.cpp, https://godbolt.org/z/38qMMWoz6:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/38qMMWoz6 
#include <mutex> // recursive_mutex
#include <iostream>
struct MulDiv {
    std::recursive_mutex mx_;
    int value_;
    explicit MulDiv(int value) : value_{value} {}
    void mul(int x) {
        std::lock_guard lk1(mx_);  // innen
        value_ *= x;
    }
    void div(int x) {
        std::lock_guard lk2(mx_);  // innen
        value_ /= x;
    }
    void muldiv(int x, int y){
        std::lock_guard lk3(mx_);  // außen
        mul(x);
        div(y);
    }
};
int main() {
   MulDiv m{42}; // 3*7*2 *5
   m.muldiv(5, 15);
   std::cout << m.value_ << '\n';  // Ausgabe: 14
}

Listing 29.28: Speicher nur für den aktuellen Thread

Book listing lst-1028-book.cpp:

// https://godbolt.org/z/1j8W7GjTf 
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
thread_local unsigned int usage = 0;
static std::mutex cout_mutex;
void use(const std::string thread_name) {
    ++usage;
    std::lock_guard lock(cout_mutex); // Ausgabe schützen
    std::cout << thread_name << ": " << usage << '\n';
}
int main() {
    std::jthread a{use, "a"}, b{use, "b"};
    use("main");
}

Godbolt Listing lst-1028-godb.cpp, https://godbolt.org/z/1j8W7GjTf:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1j8W7GjTf 
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
thread_local unsigned int usage = 0;
static std::mutex cout_mutex;
void use(const std::string thread_name) {
    ++usage;
    std::lock_guard lock(cout_mutex); // Ausgabe schützen
    std::cout << thread_name << ": " << usage << '\n';
}
int main() {
    std::jthread a{use, "a"}, b{use, "b"};
    use("main");
}

Listing 29.29: Zwei Threads kommunizieren über eine Bedingungsvariable.

Book listing lst-1030-book.cpp:

// https://godbolt.org/z/af6jK9dKo 
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <deque>
#include <iostream>
#include <syncstream>   // osyncstream
std::deque<int> g_data{};          // Datenaustausch zwischen Threads
std::condition_variable g_condvar; // benachrichtigen
std::mutex g_mx;                   // schützt g_data während Veränderungen
void produziere(int limit) {
  std::vector prims{2};          // bisherige Prims als Prüfteiler
  for(int kandidat=3; kandidat < limit; kandidat+=2) {
    for(int teiler : prims) {
      if(teiler*teiler > kandidat) {          // kandidat ist prim
        std::lock_guard lk{g_mx};             // data schützen
        g_data.push_back(kandidat);           // füllen
        g_condvar.notify_one();               // benachrichtigen
        prims.push_back(kandidat);            // für interne Berechnungen
        break; // nächster Prim-Kandidat
      } else if(kandidat % teiler == 0) {     // nicht prim
        break;                                // nächster Prim-Kandidat
      } else {
        // nächster Prüfteiler
      }
    }
  }
  // ganze Arbeit fertig mitteilen
  std::lock_guard lk{g_mx};          // data schützen
  g_data.push_back(0);               // mit Endemarkierung füllen
  g_condvar.notify_all();            // benachrichtigen
}
void konsumiere(char l, char r) {
  while(true) {                      // für immer
    std::unique_lock lk{g_mx};
    g_condvar.wait(lk, []{ return !g_data.empty();});
    int prim = g_data.front();       // Daten holen
    if(prim == 0) return;            // fertig; 0 drin lassen für andere Konsumenten
    g_data.pop_front();
    lk.unlock();                     // Sperre freigeben
    std::osyncstream osync{std::cout};  // Ausgabe synchronisieren
    osync << l << prim << r <<' ';
  }
}
int main() {
  // ein Produzent:
  std::jthread thProd{produziere, 1'000};
  // drei Konsumenten
  std::jthread thKon1{konsumiere, '[', ']' };
  std::jthread thKon2{konsumiere, '<', '>' };
  std::jthread thKon3{konsumiere, '{', '}' };
  // warten und beenden
  thProd.join();
  thKon1.join(); thKon2.join(); thKon3.join();
  std::cout << '\n';
}

Godbolt Listing lst-1030-godb.cpp, https://godbolt.org/z/af6jK9dKo:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/af6jK9dKo 
#include <thread>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <deque>
#include <iostream>
#include <syncstream>   // osyncstream
std::deque<int> g_data{};          // Datenaustausch zwischen Threads
std::condition_variable g_condvar; // benachrichtigen
std::mutex g_mx;                   // schützt g_data während Veränderungen
void produziere(int limit) {
  std::vector prims{2};          // bisherige Prims als Prüfteiler
  for(int kandidat=3; kandidat < limit; kandidat+=2) {
    for(int teiler : prims) {
      if(teiler*teiler > kandidat) {          // kandidat ist prim
        std::lock_guard lk{g_mx};             // data schützen
        g_data.push_back(kandidat);           // füllen
        g_condvar.notify_one();               // benachrichtigen
        prims.push_back(kandidat);            // für interne Berechnungen
        break; // nächster Prim-Kandidat
      } else if(kandidat % teiler == 0) {     // nicht prim
        break;                                // nächster Prim-Kandidat
      } else {
        // nächster Prüfteiler
      }
    }
  }
  // ganze Arbeit fertig mitteilen
  std::lock_guard lk{g_mx};          // data schützen
  g_data.push_back(0);               // mit Endemarkierung füllen
  g_condvar.notify_all();            // benachrichtigen
}
void konsumiere(char l, char r) {
  while(true) {                      // für immer
    std::unique_lock lk{g_mx};
    g_condvar.wait(lk, []{ return !g_data.empty();});
    int prim = g_data.front();       // Daten holen
    if(prim == 0) return;            // fertig; 0 drin lassen für andere Konsumenten
    g_data.pop_front();
    lk.unlock();                     // Sperre freigeben
    std::osyncstream osync{std::cout};  // Ausgabe synchronisieren
    osync << l << prim << r <<' ';
  }
}
int main() {
  // ein Produzent:
  std::jthread thProd{produziere, 1'000};
  // drei Konsumenten
  std::jthread thKon1{konsumiere, '[', ']' };
  std::jthread thKon2{konsumiere, '<', '>' };
  std::jthread thKon3{konsumiere, '{', '}' };
  // warten und beenden
  thProd.join();
  thKon1.join(); thKon2.join(); thKon3.join();
  std::cout << '\n';
}

Listing 29.30: »async« kann einfach asynchrone Berechnungen anstoßen.

Book listing lst-1035-book.cpp:

// https://godbolt.org/z/Gh9Y5srd7 
#include <iostream>
#include <future>  // async
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }

int main() {
    auto f40 = std::async(fib, 40);
    auto f41 = std::async(fib, 41);
    auto f42 = std::async(fib, 42);
    auto f43 = std::async(fib, 43);
    /* ... an dieser Stelle können weitere Berechnungen stehen ... */
    cout << "fib(40): " << f40.get() << endl; // Ausgabe: fib(40): 102334155
    cout << "fib(41): " << f41.get() << endl; // Ausgabe: fib(41): 165580141
    cout << "fib(42): " << f42.get() << endl; // Ausgabe: fib(42): 267914296
    cout << "fib(43): " << f43.get() << endl; // Ausgabe: fib(43): 433494437
}

Godbolt Listing lst-1035-godb.cpp, https://godbolt.org/z/Gh9Y5srd7:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Gh9Y5srd7 
#include <iostream>
#include <future>  // async
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }

int main() {
    auto f40 = std::async(fib, 40);
    auto f41 = std::async(fib, 41);
    auto f42 = std::async(fib, 42);
    auto f43 = std::async(fib, 43);
    /* ... an dieser Stelle können weitere Berechnungen stehen ... */
    cout << "fib(40): " << f40.get() << endl; // Ausgabe: fib(40): 102334155
    cout << "fib(41): " << f41.get() << endl; // Ausgabe: fib(41): 165580141
    cout << "fib(42): " << f42.get() << endl; // Ausgabe: fib(42): 267914296
    cout << "fib(43): " << f43.get() << endl; // Ausgabe: fib(43): 433494437
}

Listing 29.31: Es ist in Ordnung, ein Ergebnis nicht abzuholen.

Book listing lst-1036-book.cpp:

// https://godbolt.org/z/7Mea1Y3Mn 
#include <iostream>
#include <future>  // async
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }

int main() {
    auto f40 = std::async(fib, 40);
    auto f41 = std::async(fib, 41);
    auto f42 = std::async(fib, 42);
    auto f43 = std::async(fib, 43);
    cout << "fib(40): " << f40.get() << endl; // Ausgabe: fib(40): 102334155
} // wartet auch auf f41, f42 und f43.

Godbolt Listing lst-1036-godb.cpp, https://godbolt.org/z/7Mea1Y3Mn:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/7Mea1Y3Mn 
#include <iostream>
#include <future>  // async
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }

int main() {
    auto f40 = std::async(fib, 40);
    auto f41 = std::async(fib, 41);
    auto f42 = std::async(fib, 42);
    auto f43 = std::async(fib, 43);
    cout << "fib(40): " << f40.get() << endl; // Ausgabe: fib(40): 102334155
} // wartet auch auf f41, f42 und f43.

Listing 29.32: So erzwingen Sie die verzögerte Ausführung.

Book listing lst-1037-book.cpp:

// https://godbolt.org/z/P9MjGe6Mn 
#include <iostream>
#include <future>  // async
#include <vector>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
    // Aufgaben vorbereiten
    std::vector< std::future<long> > fibs;
    for(int n=0; n<50; ++n) {
        auto fut = std::async(std::launch::deferred, fib, n);
        fibs.push_back( std::move(fut) );
    }
    // nur das benötigte Ergebnis abholen
    cout << "fib(42): " << fibs[42].get() << endl; // Ausgabe: fib(42): 267914296
}

Godbolt Listing lst-1037-godb.cpp, https://godbolt.org/z/P9MjGe6Mn:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/P9MjGe6Mn 
#include <iostream>
#include <future>  // async
#include <vector>
using std::cout; using std::endl;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
    // Aufgaben vorbereiten
    std::vector< std::future<long> > fibs;
    for(int n=0; n<50; ++n) {
        auto fut = std::async(std::launch::deferred, fib, n);
        fibs.push_back( std::move(fut) );
    }
    // nur das benötigte Ergebnis abholen
    cout << "fib(42): " << fibs[42].get() << endl; // Ausgabe: fib(42): 267914296
}

Listing 29.33: Warten für eine gewisse Zeit bei »async«

Book listing lst-1038-book.cpp:

// https://godbolt.org/z/o9oYrvMcj 
#include <iostream>
#include <future>  // async
#include <chrono>
using std::cout; using std::endl; using namespace std::chrono;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
    auto f43 = std::async(fib, 43);
    while(true) {
        auto fertig = f43.wait_for(500ms);
        if(fertig==std::future_status::timeout) {
            std::cout << "noch nicht..." << std::endl;
        } else {
            break;
        }
    }
    // abholen, ist sofort da
    cout << "fib(43): " << f43.get() << endl; // Ausgabe: fib(43): 701408733
}

Godbolt Listing lst-1038-godb.cpp, https://godbolt.org/z/o9oYrvMcj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/o9oYrvMcj 
#include <iostream>
#include <future>  // async
#include <chrono>
using std::cout; using std::endl; using namespace std::chrono;
long fib(long n) { return n<=1 ? n : fib(n-1)+fib(n-2); }
int main() {
    auto f43 = std::async(fib, 43);
    while(true) {
        auto fertig = f43.wait_for(500ms);
        if(fertig==std::future_status::timeout) {
            std::cout << "noch nicht..." << std::endl;
        } else {
            break;
        }
    }
    // abholen, ist sofort da
    cout << "fib(43): " << f43.get() << endl; // Ausgabe: fib(43): 701408733
}

Listing 29.34: Warten auf einen Lock mit einem »timed_mutex«

Book listing lst-1039-book.cpp:

// https://godbolt.org/z/xzY8hj9oP 
#include <chrono>
#include <future>
#include <mutex>
#include <vector>
#include <iostream>
std::timed_mutex mtx;
long fibX(long n) { return n < 2L ? 1L : fibX(n-1L) + fibX(n-2L); }
long fibCall(long n) {
    using namespace std::chrono; // Suffixe
    if(mtx.try_lock_for(1000ms)) {
        auto res = fibX(n);
        mtx.unlock();
        return res;
    } else {
        return 0L;
    }
}

int main() {
    std::vector< std::future<long> > fs;
    for(long n=1; n<= 42; ++n) {
        fs.emplace_back( std::async(std::launch::async, fibCall, n) );
    }
    for(auto &f : fs) {
        std::cout << f.get() << " ";
    }
    std::cout << std::endl;
}

Godbolt Listing lst-1039-godb.cpp, https://godbolt.org/z/xzY8hj9oP:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/xzY8hj9oP 
#include <chrono>
#include <future>
#include <mutex>
#include <vector>
#include <iostream>
std::timed_mutex mtx;
long fibX(long n) { return n < 2L ? 1L : fibX(n-1L) + fibX(n-2L); }
long fibCall(long n) {
    using namespace std::chrono; // Suffixe
    if(mtx.try_lock_for(1000ms)) {
        auto res = fibX(n);
        mtx.unlock();
        return res;
    } else {
        return 0L;
    }
}

int main() {
    std::vector< std::future<long> > fs;
    for(long n=1; n<= 42; ++n) {
        fs.emplace_back( std::async(std::launch::async, fibCall, n) );
    }
    for(auto &f : fs) {
        std::cout << f.get() << " ";
    }
    std::cout << std::endl;
}

Listing 29.35: Exceptions kommen erst bei »get« beim äußeren Thread an.

Book listing lst-1040-book.cpp:

// https://godbolt.org/z/Pj63xfn7x 
#include <future> // async
#include <vector>
#include <algorithm> // max
#include <iostream>

int berechneHoehe(int count, int maxCount, int scale) {
  if(maxCount == 0)
      throw std::logic_error("Alle Hoehen 0");
  return (count * scale) / maxCount;
}

void balken(const std::vector<int> &counts) {
  // Berechnung starten
  auto maxCount = *std::max_element(counts.begin(), counts.end());
  std::vector< std::future<int> > futs;
  for(int count : counts) {
    futs.push_back(
          std::async(std::launch::async,
              berechneHoehe, count, maxCount, 200) );
  }

  // Ergebnisse einsammeln
  for(auto &fut : futs) {
    std::cout << fut.get() << ' ';                // löst Exception aus
  }
  std::cout << '\n';
}

int main() {
  try {
    balken(std::vector {10,23,13,0,33,4 });       // Ausgabe: 60 139 78 0 200 24
    balken(std::vector { 0, 0, 0, 0 });           // löst Exception aus
  } catch(std::exception &ex) {
    std::cout << "Fehler: " << ex.what() << '\n'; // Ausgabe: Fehler: Alle Hoehen 0
  }
}

Godbolt Listing lst-1040-godb.cpp, https://godbolt.org/z/Pj63xfn7x:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Pj63xfn7x 
#include <future> // async
#include <vector>
#include <algorithm> // max
#include <iostream>

int berechneHoehe(int count, int maxCount, int scale) {
  if(maxCount == 0)
      throw std::logic_error("Alle Hoehen 0");
  return (count * scale) / maxCount;
}

void balken(const std::vector<int> &counts) {
  // Berechnung starten
  auto maxCount = *std::max_element(counts.begin(), counts.end());
  std::vector< std::future<int> > futs;
  for(int count : counts) {
    futs.push_back(
          std::async(std::launch::async,
              berechneHoehe, count, maxCount, 200) );
  }

  // Ergebnisse einsammeln
  for(auto &fut : futs) {
    std::cout << fut.get() << ' ';                // löst Exception aus
  }
  std::cout << '\n';
}

int main() {
  try {
    balken(std::vector {10,23,13,0,33,4 });       // Ausgabe: 60 139 78 0 200 24
    balken(std::vector { 0, 0, 0, 0 });           // löst Exception aus
  } catch(std::exception &ex) {
    std::cout << "Fehler: " << ex.what() << '\n'; // Ausgabe: Fehler: Alle Hoehen 0
  }
}

Listing 29.36: Nur das »get« muss in »try« gekapselt werden.

Book listing lst-1041-book.cpp:

// https://godbolt.org/z/ndc4f8T3P 
#include <future> // async
#include <iostream>

int berechneHoehe(int count, int maxCount, int scale) {
  if(maxCount == 0)
      throw std::logic_error("maxCount ist 0");
  return (count * scale) / maxCount;
}

int main() {
  auto fut = std::async(std::launch::async, berechneHoehe, 0, 0, 200); //                 (ERR)  wirft
  try {
    std::cout << fut.get() << '\n';               // löst Exception aus
  } catch(std::exception &ex) {
    std::cout << "Fehler: " << ex.what() << '\n'; // Ausgabe: Fehler: maxCount ist 0
  }
}

Godbolt Listing lst-1041-godb.cpp, https://godbolt.org/z/ndc4f8T3P:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ndc4f8T3P 
#include <future> // async
#include <iostream>

int berechneHoehe(int count, int maxCount, int scale) {
  if(maxCount == 0)
      throw std::logic_error("maxCount ist 0");
  return (count * scale) / maxCount;
}

int main() {
  auto fut = std::async(std::launch::async, berechneHoehe, 0, 0, 200); //                 (ERR)  wirft
  try {
    std::cout << fut.get() << '\n';               // löst Exception aus
  } catch(std::exception &ex) {
    std::cout << "Fehler: " << ex.what() << '\n'; // Ausgabe: Fehler: maxCount ist 0
  }
}

Listing 29.37: »future« und »promise« arbeiten zusammen.

Book listing lst-1043-book.cpp:

// https://godbolt.org/z/9Ys4s5qjs 
#include <future>
#include <thread>
#include <iostream>
#include <exception>
int ack(int m, int n); // Ackermannfunktion
void langeBerechnung(std::promise<int> intPromise) {
  try {
    int result = ack(3,12);
    intPromise.set_value(result);                        // Ergebnis mitteilen
  } catch (std::exception &e) {
    intPromise.set_exception(make_exception_ptr(e));     // Exception mitteilen
  } catch ( ... ) {
    intPromise.set_exception(std::current_exception());  // Exc. ohne Namen
  }
}
int main () {
  std::promise<int> intPromise;                          // Promise erzeugen
  std::future<int> intFuture = intPromise.get_future();  // Future anfordern
  std::jthread th{ langeBerechnung,                      // starten
             std::move(intPromise) };                    // Promise übergeben
  th.detach();                                           // weiterlaufen lassen
  // könnte eine Exception werfen:
  int result = intFuture.get();                          // Ergebnis anfordern
  std::cout << result << std::endl;
}

Godbolt Listing lst-1043-godb.cpp, https://godbolt.org/z/9Ys4s5qjs:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9Ys4s5qjs 
#include <future>
#include <thread>
#include <iostream>
#include <exception>
int ack(int m, int n); // Ackermannfunktion
void langeBerechnung(std::promise<int> intPromise) {
  try {
    int result = ack(3,12);
    intPromise.set_value(result);                        // Ergebnis mitteilen
  } catch (std::exception &e) {
    intPromise.set_exception(make_exception_ptr(e));     // Exception mitteilen
  } catch ( ... ) {
    intPromise.set_exception(std::current_exception());  // Exc. ohne Namen
  }
}
int main () {
  std::promise<int> intPromise;                          // Promise erzeugen
  std::future<int> intFuture = intPromise.get_future();  // Future anfordern
  std::jthread th{ langeBerechnung,                      // starten
             std::move(intPromise) };                    // Promise übergeben
  th.detach();                                           // weiterlaufen lassen
  // könnte eine Exception werfen:
  int result = intFuture.get();                          // Ergebnis anfordern
  std::cout << result << std::endl;
}

Listing 29.38: Packaged Task vorbereiten für die spätere Ausführung

Book listing lst-1044-book.cpp:

// https://godbolt.org/z/9s94nbrx3 
#include <future>
#include <thread>
#include <iostream>
int ack(int m, int n); // Ackermannfunktion
int main () {
    std::packaged_task<int(void)> task1 {          // Signatur der Restfunktion
    []{ return ack(3,11);}  };                     // ack(3,11) vorbereiten
  auto f1 = task1.get_future();                    // Kommunikationskanal
  std::jthread th1 { move(task1) };                // in neuen Thread
  std::cout << "  ack(3,11):" << f1.get()          // Ergebnis abholen
      << '\n';                                     // Ausgabe: ack(3,11):16381
}

Godbolt Listing lst-1044-godb.cpp, https://godbolt.org/z/9s94nbrx3:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/9s94nbrx3 
#include <future>
#include <thread>
#include <iostream>
int ack(int m, int n); // Ackermannfunktion
int main () {
    std::packaged_task<int(void)> task1 {          // Signatur der Restfunktion
    []{ return ack(3,11);}  };                     // ack(3,11) vorbereiten
  auto f1 = task1.get_future();                    // Kommunikationskanal
  std::jthread th1 { move(task1) };                // in neuen Thread
  std::cout << "  ack(3,11):" << f1.get()          // Ergebnis abholen
      << '\n';                                     // Ausgabe: ack(3,11):16381
}

Listing 29.39: Packaged Task erst später mit Argumenten versorgen

Book listing lst-1045-book.cpp:

// https://godbolt.org/z/bq1hn5rjo 
#include <future>
#include <thread>
#include <iostream>
int ack(int m, int n); // Ackermannfunktion
int main () {
  std::packaged_task<int(int,int)> task2 { &ack }; // andere Signatur
  auto f2 = task2.get_future();
  std::jthread th2 { move(task2), 3, 12 };         // Parameter hier
  std::cout << "  ack(3,12):" << f2.get() << '\n'; // Ausgabe: ack(3,12):32765
  th2.join();
}

Godbolt Listing lst-1045-godb.cpp, https://godbolt.org/z/bq1hn5rjo:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/bq1hn5rjo 
#include <future>
#include <thread>
#include <iostream>
int ack(int m, int n); // Ackermannfunktion
int main () {
  std::packaged_task<int(int,int)> task2 { &ack }; // andere Signatur
  auto f2 = task2.get_future();
  std::jthread th2 { move(task2), 3, 12 };         // Parameter hier
  std::cout << "  ack(3,12):" << f2.get() << '\n'; // Ausgabe: ack(3,12):32765
  th2.join();
}

Listing 29.40: So finden Sie heraus, ob die Operationen sperrfrei sind.

Book listing lst-1046-book.cpp:

// https://godbolt.org/z/3Y5WP6qWM 
#include <iostream>
#include <atomic>

struct CArray { int a[100]; };
struct Einfach { int x, y; };

int main() {
    std::atomic<CArray> carray{};
    std::cout << (carray.is_lock_free() ? "sperrfrei" : "sperrt")
        << '\n';                                        // Ausgabe: sperrt
    std::atomic<Einfach> einfach{};
    std::cout << (einfach.is_lock_free() ? "sperrfrei" : "sperrt")
        << '\n';                                        // Ausgabe: sperrfrei
}

Godbolt Listing lst-1046-godb.cpp, https://godbolt.org/z/3Y5WP6qWM:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/3Y5WP6qWM 
#include <iostream>
#include <atomic>

struct CArray { int a[100]; };
struct Einfach { int x, y; };

int main() {
    std::atomic<CArray> carray{};
    std::cout << (carray.is_lock_free() ? "sperrfrei" : "sperrt")
        << '\n';                                        // Ausgabe: sperrt
    std::atomic<Einfach> einfach{};
    std::cout << (einfach.is_lock_free() ? "sperrfrei" : "sperrt")
        << '\n';                                        // Ausgabe: sperrfrei
}

Listing 29.41: Die Klasse »SpinlockMutex« verhindert das Schlafenlegen beim Warten.

Book listing lst-1047-book.cpp:

// https://godbolt.org/z/W47YTYcEb 
#include <atomic>
class SpinlockMutex {
  std::atomic_flag flag_;
public:
  SpinlockMutex()
  : flag_{ATOMIC_FLAG_INIT}
  {}
  void lock() {                                 // z. B. von lock_guard aufgerufen
    while(flag_.test_and_set(std::memory_order_acquire)) // hauptsächlich lesen
      { /* nothing */ }
  }
  void unlock() {
    flag_.clear(std::memory_order_release);              // Schreiboperation
  }
};

Godbolt Listing lst-1047-godb.cpp, https://godbolt.org/z/W47YTYcEb:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/W47YTYcEb 
#include <atomic>
class SpinlockMutex {
  std::atomic_flag flag_;
public:
  SpinlockMutex()
  : flag_{ATOMIC_FLAG_INIT}
  {}
  void lock() {                                 // z. B. von lock_guard aufgerufen
    while(flag_.test_and_set(std::memory_order_acquire)) // hauptsächlich lesen
      { /* nothing */ }
  }
  void unlock() {
    flag_.clear(std::memory_order_release);              // Schreiboperation
  }
};

Listing 29.42: Ihre Koroutine liefert einen »generator« zurück.

Book listing lst-1048-book.cpp:

// https://godbolt.org/z/Gfazq6GE7 
#include <generator>
#include <iostream>
#include <vector>

std::generator<int> fib(int n) { // generiert int-Werte
  int a = 0, b = 1;
  while (--n) {
    co_yield b;                  // macht diese Funktion zu einer Koroutine
    auto tmp = a;
    a = b;
    b += tmp;
  }
}
int main() {
  for (auto i : fib(10)) std::cout << i << ' ';
  std::cout << '\n';             // Ausgabe: 1 1 2 3 5 8 13 21 34 55
}

Godbolt Listing lst-1048-godb.cpp, https://godbolt.org/z/Gfazq6GE7:

//#(compile) c++; compiler:gsnapshot; options:"-std=c++23"; libs:-
// https://godbolt.org/z/Gfazq6GE7 
#include <generator>
#include <iostream>
#include <vector>

std::generator<int> fib(int n) { // generiert int-Werte
  int a = 0, b = 1;
  while (--n) {
    co_yield b;                  // macht diese Funktion zu einer Koroutine
    auto tmp = a;
    a = b;
    b += tmp;
  }
}
int main() {
  for (auto i : fib(10)) std::cout << i << ' ';
  std::cout << '\n';             // Ausgabe: 1 1 2 3 5 8 13 21 34 55
}

Listing 29.43: Ein einfaches Beispiel für einen Koroutinen-Rückgabetyp mit seinem »promise_type«

Book listing lst-1049-book.cpp:

// https://godbolt.org/z/4ed3oWK7q 
#include <coroutine>
#include <iostream>
struct Routine { // Koroutinen-Rückgabetyp
  struct promise_type;                     // weiter unten definiert
  Routine(auto h) : hdl_(h) {}             // Konstruktor
  ~Routine() { if(hdl_) hdl_.destroy(); }  // Destruktor
  Routine(const Routine&) = delete;        // keine Kopien
  Routine(Routine&&) = delete;             // keine Verschiebungen
  // Schnittstelle für den Aufrufer:
  bool more() {                            // Koroutine fortsetzen
    if(!hdl_ || hdl_.done()) return false; // - nichts mehr zu tun
    hdl_.resume();                         // - blockierender Aufruf
    return !hdl_.done();                   // - signalisiert fertig oder nicht
  }
private:
  using handle_type_ = std::coroutine_handle<promise_type>;
  handle_type_ hdl_;     // zum Steuern der Koroutine
};
struct Routine::promise_type {             // notwendiger promise_type
  auto get_return_object() {               // initialisiert das Handle
    return Routine{ handle_type_::from_promise(*this) };
  }
  auto initial_suspend() { return std::suspend_never{}; } // sofort starten
  auto final_suspend() noexcept { return std::suspend_always{}; } // Normalfall
  void unhandled_exception() {}                 // keine Exception-Behandlung
  void return_void() {}                         // Koroutine hat keine Rückgabe
};
Routine counter() {  // Rückgabetyp ist unsere Wrapperklasse mit dem promise_type
  for (unsigned i = 0;; ++i) {
    co_await std::suspend_always{};             // Koroutine pausieren
    std::cout << "counter: " << i << std::endl;
  }
}

int main() {
  Routine routine = counter();                  // Koroutine erzeugen und starten
  for (int i = 0; i < 3; ++i) {
      std::cout << "Hallo main!\n";
      routine.more();                           // Koroutine fortsetzen
  }
}

Godbolt Listing lst-1049-godb.cpp, https://godbolt.org/z/4ed3oWK7q:

//#(compile) c++; compiler:g132; options:"-std=c++20"; libs:-
// https://godbolt.org/z/4ed3oWK7q 
#include <coroutine>
#include <iostream>
struct Routine { // Koroutinen-Rückgabetyp
  struct promise_type;                     // weiter unten definiert
  Routine(auto h) : hdl_(h) {}             // Konstruktor
  ~Routine() { if(hdl_) hdl_.destroy(); }  // Destruktor
  Routine(const Routine&) = delete;        // keine Kopien
  Routine(Routine&&) = delete;             // keine Verschiebungen
  // Schnittstelle für den Aufrufer:
  bool more() {                            // Koroutine fortsetzen
    if(!hdl_ || hdl_.done()) return false; // - nichts mehr zu tun
    hdl_.resume();                         // - blockierender Aufruf
    return !hdl_.done();                   // - signalisiert fertig oder nicht
  }
private:
  using handle_type_ = std::coroutine_handle<promise_type>;
  handle_type_ hdl_;     // zum Steuern der Koroutine
};
struct Routine::promise_type {             // notwendiger promise_type
  auto get_return_object() {               // initialisiert das Handle
    return Routine{ handle_type_::from_promise(*this) };
  }
  auto initial_suspend() { return std::suspend_never{}; } // sofort starten
  auto final_suspend() noexcept { return std::suspend_always{}; } // Normalfall
  void unhandled_exception() {}                 // keine Exception-Behandlung
  void return_void() {}                         // Koroutine hat keine Rückgabe
};
Routine counter() {  // Rückgabetyp ist unsere Wrapperklasse mit dem promise_type
  for (unsigned i = 0;; ++i) {
    co_await std::suspend_always{};             // Koroutine pausieren
    std::cout << "counter: " << i << std::endl;
  }
}

int main() {
  Routine routine = counter();                  // Koroutine erzeugen und starten
  for (int i = 0; i < 3; ++i) {
      std::cout << "Hallo main!\n";
      routine.more();                           // Koroutine fortsetzen
  }
}

GodboltId:veEq4dcET

Book listing lst-1052-book.cpp:

// https://godbolt.org/z/veEq4dcET 
struct Tag {
    Tag(int a, int b) : Tag{} {       // delegiert
        if(a==0 || b == 0)
            throw 666;                // löst Ausnahme aus
    }
    Tag() {}
};
int main() {
    try {
        Tag tag{1,2};
    } catch(int) { }
}

Godbolt Listing lst-1052-godb.cpp, https://godbolt.org/z/veEq4dcET:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/veEq4dcET 
struct Tag {
    Tag(int a, int b) : Tag{} {       // delegiert
        if(a==0 || b == 0)
            throw 666;                // löst Ausnahme aus
    }
    Tag() {}
};
int main() {
    try {
        Tag tag{1,2};
    } catch(int) { }
}

GodboltId:Y8KK3nEG3

Book listing lst-1057-book.cpp:

// https://godbolt.org/z/Y8KK3nEG3
void sortData(std::ranges::random_access_range auto &&data) {
    std::ranges::sort(data);
}

Godbolt Listing lst-1057-godb.cpp, https://godbolt.org/z/Y8KK3nEG3:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/Y8KK3nEG3
void sortData(std::ranges::random_access_range auto &&data) {
    std::ranges::sort(data);
}