CodeNebula
C++26stlexpert

std::expected Monadic Operations (C++26 Evolution)

C++26 · The Next Frontier · Compiler flag: -std=c++26

Explanation

Adds `and_then`, `transform`, and `or_else` to `std::expected` for monadic operations.

Real-World Scenario

Handle file operation results with chained error handling.

Quick Snippet

snippet.cpp
#include <expected> auto result = exp.transform([](int x) { return x * x; });

Full Example

expected_monadic.cpp
// CodeNebula - C++26 Example: std::expected Monadic Improvements
// Compile: g++ -std=c++26 -Wall -Wextra -o example expected_monadic.cpp
// Note: Requires C++26 compiler support

#include <iostream>
#include <string>
#include <functional>

// C++23 added std::expected with and_then, transform, or_else, transform_error.
// C++26 improves with: fully constexpr chains, optional interop, better CTAD.

namespace sim {
    template <typename T, typename E>
    class expected {
        bool has_val_; union { T val_; E err_; };
    public:
        expected(T v) : has_val_(true), val_(std::move(v)) {}
        struct unexpected_tag {};
        expected(unexpected_tag, E e) : has_val_(false), err_(std::move(e)) {}
        ~expected() { if (has_val_) val_.~T(); else err_.~E(); }
        bool has_value() const { return has_val_; }
        const T& value() const { return val_; }
        const E& error() const { return err_; }

        template <typename F>
        auto and_then(F f) const -> decltype(f(val_)) {
            if (has_val_) return f(val_);
            using R = decltype(f(val_));
            return R(typename R::unexpected_tag{}, err_);
        }
        template <typename F>
        auto transform(F f) const -> expected<decltype(f(val_)), E> {
            if (has_val_) return {f(val_)};
            return {unexpected_tag{}, err_};
        }
        template <typename F>
        auto or_else(F f) const -> expected {
            if (has_val_) return *this; return f(err_);
        }
    };
    template <typename T, typename E>
    expected<T, E> make_unexpected(E e) {
        return expected<T, E>(typename expected<T, E>::unexpected_tag{}, std::move(e));
    }
}

int main() {
    std::cout << "--- std::expected Monadic (C++26) ---\n\n";
    using Result = sim::expected<int, std::string>;

    auto parse = [](const std::string& s) -> Result {
        if (s.empty()) return sim::make_unexpected<int, std::string>("empty input");
        return std::stoi(s);
    };
    auto validate = [](int v) -> Result {
        if (v < 0) return sim::make_unexpected<int, std::string>("negative");
        return v;
    };

    auto ok = parse("42").and_then(validate).transform([](int v) { return v * 2; });
    std::cout << "Success: " << ok.value() << "\n";

    auto err = parse("").and_then(validate);
    std::cout << "Error:   \"" << err.error() << "\"\n";

    auto recovered = parse("").or_else([](const std::string&) -> Result { return 0; });
    std::cout << "Recover: " << recovered.value() << "\n";
    std::cout << "\nC++26 makes these chains fully constexpr.\n";
    return 0;
}

// Expected output:
// --- std::expected Monadic (C++26) ---
//
// Success: 84
// Error:   "empty input"
// Recover: 0
//
// C++26 makes these chains fully constexpr.
Run command
g++ -std=c++26 -Wall -Wextra -o example expected_monadic.cpp