Section

std::expected

The class template std::expected provides a way to represent either of two values: an expected value of type T, or an unexpected value of type E. std::expected is never valueless.

# Declarations

template< class T, class E >
class expected;

(since C++23)

template< class T, class E >
requires std::is_void_v<T>
class expected<T, E>;

(since C++23)

# Template parameters

  • T: the type of the expected value. It may be void, or any type that satisfies the Destructible requirements. Array and reference types are not allowed.
  • E: the type of the unexpected value. It must satisfy the Destructible requirements and be a valid template argument for std::unexpected. Arrays, cv-qualified types, and non-object types are not allowed.

# Member types

Member typeDefinition
value_typeT
error_typeE
unexpected_typestd::unexpected<E>

# Member alias templates

Alias templateDefinition
template<class U> using rebindstd::expected<U, error_type>

# Data members

These exposition-only members describe the stored state:

MemberDescription
bool has_valIndicates whether the object currently contains the expected value.
T valStores the expected value in the primary template.
E unexStores the unexpected value when no expected value is present.

# Member functions

# Construction and assignment

MemberDescription
expected::expectedConstructs an expected object.
expected::~expectedDestroys the contained value or error state.
expected::operator=Replaces the contained state by assignment.

# Observers

MemberDescription
operator->, operator*Access the expected value directly.
operator bool, has_valueCheck whether the object contains an expected value.
valueReturns the expected value, throwing on error access.
errorReturns the stored unexpected value.
value_orReturns the expected value or a supplied fallback.
error_orReturns the unexpected value or a supplied fallback.

# Monadic operations

MemberDescription
and_thenInvokes a function on the expected value and returns its expected result.
transformMaps the expected value while preserving the error channel.
or_elseInvokes a function on the error value and returns the resulting expected.
transform_errorMaps the error value while preserving success values.

# Modifiers

MemberDescription
emplaceConstructs the expected value in place.
swapExchanges the contained states of two expected objects.

# Non-member functions

FunctionDescription
operator==Compares two expected objects, or an expected with a value/error-like counterpart.
swapSpecializes std::swap for std::expected.

# Helper classes

HelperDescription
unexpectedWraps an unexpected value explicitly.
bad_expected_accessException type thrown by checked accessors when no expected value is present.
unexpect, unexpect_tTag type and tag object used for in-place construction of the unexpected state.

# Notes

std::expected models operations that may either produce a value or report a domain-specific error without forcing exception-based control flow. Unlike std::optional, the disengaged state carries a typed error payload.

The void specialization represents operations that succeed without producing a value. In that form, the object still records success versus failure, but only the error branch stores user data.

Types with the same functionality are called Result in Rust and Either in Haskell.

# Feature-test macro

MacroValueStandardMeaning
__cpp_lib_expected202202LC++23std::expected and its helper types
__cpp_lib_expected202211LC++23Monadic operations such as and_then and transform

# Example

#include <cmath>
#include <expected>
#include <iomanip>
#include <iostream>
#include <string_view>
 
enum class parse_error
{
    invalid_input,
    overflow
};
 
auto parse_number(std::string_view& str) -> std::expected<double, parse_error>
{
    const char* begin = str.data();
    char* end;
    double retval = std::strtod(begin, &end);
 
    if (begin == end)
        return std::unexpected(parse_error::invalid_input);
    else if (std::isinf(retval))
        return std::unexpected(parse_error::overflow);
 
    str.remove_prefix(end - begin);
    return retval;
}
 
int main()
{
    auto process = [](std::string_view str)
    {
        std::cout << "str: " << std::quoted(str) << ", ";
        if (const auto num = parse_number(str); num.has_value())
            std::cout << "value: " << *num << '\n';
            // If num did not have a value, dereferencing num
            // would cause an undefined behavior, and
            // num.value() would throw std::bad_expected_access.
            // num.value_or(123) uses specified default value 123.
        else if (num.error() == parse_error::invalid_input)
            std::cout << "error: invalid input\n";
        else if (num.error() == parse_error::overflow)
            std::cout << "error: overflow\n";
        else
            std::cout << "unexpected!\n"; // or invoke std::unreachable();
    };
 
    for (auto src : {"42", "42abc", "meow", "inf"})
        process(src);
}

# References

  • C++23 standard (ISO/IEC 14882:2024): 22.8 Expected objects [expected]

# See also