C++23stlexpert
std::variant Monadic Operations (C++23 Addition)
C++23 · Completing Modern · Compiler flag: -std=c++23
Explanation
Adds `and_then` and `transform` for monadic-style operations on variants.
Real-World Scenario
Transform variant data in a game’s event system.
Quick Snippet
snippet.cpp
#include <variant> auto result = var.transform([](int x) { return x * x; });Full Example
variant_monadic.cpp
// CodeNebula - C++23 Example: std::variant Monadic Operations
// Compile: g++ -std=c++23 -Wall -Wextra -o example variant_monadic.cpp
// Note: Requires GCC 13+ / Clang 17+
#include <iostream>
#include <string>
#include <variant>
// C++23 adds std::visit improvements for variants:
// - Deducing this enables visit as a member-like pattern
// - Overload set pattern is more ergonomic
// Note: True monadic operations (and_then/transform) are not part of
// std::variant in C++23, but visit improvements make similar patterns easier.
// A simple result type using variant
using Result = std::variant<int, std::string>;
// Overload helper (now cleaner with C++23 CTAD improvements)
template <class... Ts>
struct overloaded : Ts... { using Ts::operator()...; };
// Process variant with visitor
Result parse_value(const std::string& input) {
try {
return std::stoi(input);
} catch (...) {
return "Error: '" + input + "' is not a number";
}
}
// Transform a Result: double the int, or prefix the error
Result transform_result(const Result& r) {
return std::visit(overloaded{
[](int v) -> Result { return v * 2; },
[](const std::string& err) -> Result {
return "Transformed: " + err;
}
}, r);
}
// Chain: only proceed if int, else keep error
Result and_then_positive(const Result& r) {
return std::visit(overloaded{
[](int v) -> Result {
if (v > 0) return v;
return std::string("Error: value is not positive");
},
[](const std::string& err) -> Result { return err; }
}, r);
}
void print_result(const char* label, const Result& r) {
std::cout << label << ": ";
std::visit(overloaded{
[](int v) { std::cout << "int(" << v << ")\n"; },
[](const std::string& s) { std::cout << "string(\"" << s << "\")\n"; }
}, r);
}
int main() {
std::cout << "=== std::variant monadic-style operations ===\n\n";
// Parse and process
auto r1 = parse_value("42");
auto r2 = parse_value("hello");
auto r3 = parse_value("-5");
print_result("parse(\"42\")", r1);
print_result("parse(\"hello\")", r2);
print_result("parse(\"-5\")", r3);
// Transform (map-like)
std::cout << "\n--- transform (double int / prefix error) ---\n";
print_result("transform(42)", transform_result(r1));
print_result("transform(hello)", transform_result(r2));
// and_then (flatmap-like)
std::cout << "\n--- and_then (check positive) ---\n";
print_result("positive(42)", and_then_positive(r1));
print_result("positive(-5)", and_then_positive(r3));
print_result("positive(hello)", and_then_positive(r2));
// Chaining operations
std::cout << "\n--- Chaining ---\n";
auto chain = [](const std::string& input) {
auto parsed = parse_value(input);
auto positive = and_then_positive(parsed);
return transform_result(positive);
};
print_result("chain(\"42\")", chain("42"));
print_result("chain(\"-5\")", chain("-5"));
print_result("chain(\"abc\")", chain("abc"));
return 0;
}
// Expected output:
// === std::variant monadic-style operations ===
//
// parse("42"): int(42)
// parse("hello"): string("Error: 'hello' is not a number")
// parse("-5"): int(-5)
//
// --- transform (double int / prefix error) ---
// transform(42): int(84)
// transform(hello): string("Transformed: Error: 'hello' is not a number")
//
// --- and_then (check positive) ---
// positive(42): int(42)
// positive(-5): string("Error: value is not positive")
// positive(hello): string("Error: 'hello' is not a number")
//
// --- Chaining ---
// chain("42"): int(84)
// chain("-5"): string("Transformed: Error: value is not positive")
// chain("abc"): string("Transformed: Error: 'abc' is not a number")
Run command
g++ -std=c++23 -Wall -Wextra -o example variant_monadic.cpp