Edge Rewrite
Jump to content

Draft:Std::expected

From Wikipedia, the free encyclopedia

std::expected is a class template in the C++ Standard Library introduced in C++23. It is a vocabulary type that represents either an expected value of type T or an unexpected value of type E.[1] It is intended for functions that may either produce a value or report an error without using exceptions.[2] The class template is defined in the <expected> header.

Background and design

[edit]

Historically, error handling in C++ has relied primarily on two strategies: returning status/error codes or throwing standard C++ exceptions. While exceptions allow for clean separation of happy-path logic from error handling, they introduce non-deterministic performance characteristics, potential binary size bloat, and require runtime support stack unwinding.[3] As a result, codebases in safety-critical, real-time, or embedded software development frequently disallow exceptions using compiler flags such as -fno-exceptions.[4]

Conversely, traditional status codes require out-of-band error return channels (such as output parameters) or forced sentinel values, which can obscure function signatures and invite unhandled runtime failures if callers ignore return codes.[5]

While std::optional was added in C++17 to convey the presence or absence of a value, it carries no explicit context regarding *why* an operation failed. std::expected bridges this gap by marrying the safety of explicit return values with detailed error payload reporting.

The conceptual origins of std::expected stem from functional programming constructs, most notably the Either monad. The C++ design drew heavy inspiration from Andrei Alexandrescu's 2012 talk and paper on "Systematic Error Handling", as well as error handling abstractions in modern systems languages such as Rust's Result<T, E> type.[1]

Semantics

[edit]

An instance of std::expected<T, E> represents a discriminated union containing either:

  • an expected value of type T, or
  • an unexpected value of type E representing an error state.

Unlike polymorphic pointer types, std::expected stores its underlying value directly within its memory footprint (typically allocating enough storage for the larger of T or E plus a boolean flag), avoiding dynamic heap allocation. The type is guaranteed to never be valueless.

Specializations exist for cases where T is void (i.e., std::expected<void, E>), enabling functions that return no meaningful result on success to still communicate failure metadata.

History

[edit]

The effort to standardise expected values in C++ began with proposal paper P0323, presented to the ISO C++ Standards Committee (WG21). Following extensive design revisions across several years, the revision P0323R12 was officially accepted for inclusion in C++23.[1]

In parallel, standardisation efforts aimed at equipping C++ vocabulary types with functional composition tools led to the acceptance of paper P2505R5. This added monadic member functions (such as and_then, transform, and or_else) to both std::optional and std::expected, enabling clean operation chaining without requiring nested conditional checks.[6]

Interface

[edit]

The class template provides standard observers to query state and access contained values:

  • has_value() – checks whether the object contains an expected value.
  • value() – returns the contained value, or throws std::bad_expected_access if the object contains an error.
  • error() – accesses the underlying error object.
  • value_or() – returns the contained value or a provided fallback default.

Monadic operations

[edit]

C++23 monadic utilities facilitate functional operation chaining:

  • and_then() – executes a function returning an expected if a value is present.
  • transform() – applies a transformation function to the expected value.
  • or_else() – executes a recovery routine returning an expected if an error state is present.
  • transform_error() – applies a transformation function specifically to the stored error type.

The standard library also defines helper utilities: std::unexpected (a wrapper used to signal error construction), std::unexpect_t / std::unexpect (in-place tagging utilities), and std::bad_expected_access (the exception type thrown on invalid access).

Example

[edit]

The following example demonstrates basic usage, returning an error payload on division by zero:

#include <expected>
#include <iostream>
#include <string>

std::expected<double, std::string> safe_divide(double numerator, double denominator)
{
    if (denominator == 0.0)
        return std::unexpected("Error: Division by zero.");

    return numerator / denominator;
}

int main()
{
    auto result = safe_divide(10.0, 2.0);

    if (result.has_value()) {
        std::cout << "Result: " << result.value() << '\n';
    } else {
        std::cerr << result.error() << '\n';
    }

    // Example of monadic chaining
    auto chained = safe_divide(10.0, 2.0)
        .transform([](double v) { return v * 2.0; })
        .value_or(0.0);

    std::cout << "Chained result: " << chained << '\n';
}

See also

[edit]

References

[edit]
  1. 1 2 3 Rapposov, Vicente J. Botet; Loshkaloff, LWG (2022-05-15). "P0323R12: std::expected". ISO/IEC JTC1/SC22/WG21. Retrieved 7 August 2026.
  2. "std::expected". cppreference.com. Retrieved 7 August 2026.
  3. Grimm, Rainer (2023). C++23: The Core Language and Library. Leanpub. pp. 142–148.
  4. Williams, Anthony (2019). C++ Concurrency in Action (2nd ed.). Manning. ISBN 978-1617294693.
  5. Josuttis, Nicolai (2012). The C++ Standard Library: A Tutorial and Reference (2nd ed.). Addison-Wesley. ISBN 978-0321563842.
  6. Sy Brand (2022-07-06). "P2505R5: Monadic Functions for std::expected". ISO/IEC JTC1/SC22/WG21. Retrieved 7 August 2026.

Category:C++ Category:Standard Template Library