Siehe das Beispiel im korrespondierenden Quellcode.
Ab C++ 23 wurden zur Klasse std::optional neue Operationen hinzugefügt: and_then, or_else und transform.
Diese Operationen, die von Konzepten der funktionalen Programmierung inspiriert sind,
bieten eine prägnantere und ausdrucksstärkere Möglichkeit,
mit optionalen Werten (also mit std::optional-Objekten) zu arbeiten,
Die monadischen Interfaces (eingeführt mit C++ 23) bringen vor allem Eleganz und Sicherheit in den Code. Hier sind die wichtigsten Vorteile:
- Vermeidung von „if-Pyramiden„:
Statt verschachtelterif (opt.has_value())-Abfragen kann man Operationen einfach mit.and_then()oder.transform()verketten. Das hält den Code flach und lesbar. - Deklarativer Stil:
Der Fokus liegt auf dem Was (der Logik) statt auf dem Wie (dem Error-Handling). Der Kontrollfluss für Fehlerfälle ist implizit eingebaut. - Sicheres Pipelining:
Wenn ein Glied in der Kettestd::nulloptoder einen Fehler zurückgibt, wird der Rest der Kette automatisch übersprungen. Man muss nicht bei jedem Zwischenschritt manuell prüfen. - Kompaktheit:
Komplexe Transformationen, die früher mehrere Zeilen Boilerplate-Code erforderten, lassen sich oft in einem einzigen Ausdruck (Expression) formulieren.
Kurz gesagt: Es macht Quellcode funktionaler und weniger fehleranfällig gegenüber vergessenen Null-Checks.
Die Funktion and_then ermöglicht die Verkettung von Funktionen, die einen std::optional-Wert zurückgeben.
Enthält das std::optional-Objekt, auf dem and_then aufgerufen wird, einen Wert,
wird die angegebene Funktion mit diesem Wert aufgerufen.
Das std::optional-Objekt wird gewissermaßen ausgepackt.
Bei erfolgreichem Funktionsaufruf wird ein Ergebnis zurückgegeben,
andernfalls wird ein leeres std::optional-Objekt zurückgegeben.
Beispiel:
01: void test()
02: {
03: std::optional<int> n{ 123 };
04:
05: auto result = n.and_then([](auto x) {
06: if (x == 123) {
07: return std::optional<std::string>("Got expected value 123");
08: }
09: else {
10: return std::optional<std::string>("Got unexpected value! ");
11: }
12: });
13:
14: if (result) {
15: std::println("{}", result.value());
16: }
17:
18: std::println("Done.");
19: }Ausgabe:
Got expected value 123
Die Funktion and_then() erwartet eine Funktion, die einen Wert vom Typ des in std::optional enthaltenen Objekts entgegennimmt
und ein anderes std::optional-Objekt zurückgibt.
Die Anforderungen an die in and_then() übergebene Funktion sind wie folgt:
- Eingabetyp:
Die Funktion muss ein einzelnes Argument akzeptieren. Der Typ dieses Arguments muss mit dem Typ des Werts imstd::optional-Objekt übereinstimmen, auf demand_then()aufgerufen wird. - Rückgabetyp:
Die Funktion muss einstd::optional<U>-Objekt zurückgeben, wobeiUein beliebiger Typ sein kann.
Wir betrachten ein zweites, realitätsnahes Beispiel. Es geht um User-Objekte:
01: class User
02: {
03: public:
04: std::string m_first;
05: std::string m_last;
06: std::size_t m_age;
07: };Der Einfachheit halber legen wir fest, dass ein User-Objekt einen gültigen Namen besitzt,
wenn die beiden Zeichenketten des Vor- und Nachnamens nicht leer sind.
Mit der Funktion and_then() können wir auf einem gültigen std::optional<User> eine Nachverarbeitung
der in der Klasse User vorhandenen Informationen vornehmen:
Beispiel:
01: std::optional<std::string> hasValidName(const User& user) {
02: if (!user.m_first.empty() and !user.m_last.empty()) {
03: return user.m_first + " " + user.m_last;
04: }
05: else {
06: return std::nullopt;
07: }
08: }
09:
10: void test()
11: {
12: auto user = std::make_optional<User>("Hans", "Mueller", 30);
13:
14: auto result = user.and_then([](const auto& user) {
15: return hasValidName(user);
16: });
17:
18: if (result) {
19: std::println("Result: {}", result.value());
20: }
21: }Ausgabe:
Result: Hans Mueller
Die or_else-Operation ermöglicht es, eine Alternative für den Fall festzulegen,
dass std::optional leer ist. Enthält std::optional einen Wert, wird dieser unverändert durchgereicht.
Ist er leer, wird die angegebene Funktion aufgerufen und deren Ergebnis (das ebenfalls ein std::optional sein sollte) zurückgegeben.
Beispiel:
01: void test()
02: {
03: auto user = std::make_optional<User>("Hans", "Mueller", 30);
04:
05: auto result = user.and_then([](const auto& user) {
06: return hasValidName(user);
07: }).or_else([]() {
08: return std::optional<std::string>{"Max Mustermann"};
09: });
10:
11: if (result) {
12: std::println("Result: {}", result.value());
13: }
14: }Ausgabe:
Result: Hans Mueller
Stimmt an dem Vor- oder Nachnamen etwas nicht, erhält man die Ausgabe
Result: Max Mustermann
Die transform-Operation ähnelt and_then, jedoch mit einem entscheidenden Unterschied:
Die an transform übergebene Funktion gibt einen einfachen Wert zurück, kein std::optional.
Dieser Wert wird dann in ein neues std::optional-Objekt eingeschlossen.
Ist das ursprüngliche std::optional-Objekt leer, wird die Funktion nicht aufgerufen und es wird ein leeres std::optional-Objekt zurückgegeben.
Beispiel:
01: void test()
02: {
03: auto user = std::make_optional<User>("Hans", "Mueller", 30);
04:
05: auto result = user.and_then([](const auto& user) {
06: return hasValidName(user);
07: }).transform([](auto name) {
08:
09: std::transform(
10: name.begin(),
11: name.end(),
12: name.begin(),
13: [](unsigned char c) { return std::toupper(c); }
14: );
15:
16: return name;
17: });
18:
19: if (result) {
20: std::println("Result: {}", result.value());
21: }
22: }Ausgabe:
Result: HANS MUELLER
Die Anregungen zu diesem Code-Snippet finden sich unter anderem unter
std::optional
(abgerufen am 23.05.2020).
Modern C++ Features – std::optional
(abgerufen am 23.05.2020).
Quick tip: How to return std::optional from a function
(abgerufen am 23.05.2020).
Zu den Erweiterungen ab C++ 23 – neue monadische Funktionen – gibt es die folgenden beiden interessanten Artikel:
How to Use Monadic Operations for std::optional in C++ 23
(abgerufen am 08.04.2026).
Daily bit(e) of C++ | Monadic interface for std::optional
(abgerufen am 08.04.2026).