22 General utilities library [utilities]

22.8 Expected objects [expected]

22.8.1 In general [expected.general]

Subclause [expected] describes the class template expected that represents expected objects.
An expected<T, E> object holds an object of type T or an object of type E and manages the lifetime of the contained objects.

22.8.2 Header <expected> synopsis [expected.syn]

// mostly freestanding namespace std { // [expected.unexpected], class template unexpected template<class E> class unexpected; // [expected.bad], class template bad_expected_access template<class E> class bad_expected_access; // [expected.bad.void], specialization for void template<> class bad_expected_access<void>; // in-place construction of unexpected values struct unexpect_t { explicit unexpect_t() = default; }; inline constexpr unexpect_t unexpect{}; // [expected.expected], class template expected template<class T, class E> class expected; // partially freestanding // [expected.void], partial specialization of expected for void types template<class T, class E> requires is_void_v<T> class expected<T, E>; // partially freestanding }

22.8.3 Class template unexpected [expected.unexpected]

22.8.3.1 General [expected.un.general]

Subclause [expected.unexpected] describes the class template unexpected that represents unexpected objects stored in expected objects.
namespace std { template<class E> class unexpected { public: // [expected.un.cons], constructors constexpr unexpected(const unexpected&) = default; constexpr unexpected(unexpected&&) = default; template<class Err = E> constexpr explicit unexpected(Err&&); template<class... Args> constexpr explicit unexpected(in_place_t, Args&&...); template<class U, class... Args> constexpr explicit unexpected(in_place_t, initializer_list<U>, Args&&...); constexpr unexpected& operator=(const unexpected&) = default; constexpr unexpected& operator=(unexpected&&) = default; constexpr const E& error() const & noexcept; constexpr E& error() & noexcept; constexpr const E&& error() const && noexcept; constexpr E&& error() && noexcept; constexpr void swap(unexpected& other) noexcept(see below); template<class E2> friend constexpr bool operator==(const unexpected&, const unexpected<E2>&); friend constexpr void swap(unexpected& x, unexpected& y) noexcept(noexcept(x.swap(y))); private: E unex; // exposition only }; template<class E> unexpected(E) -> unexpected<E>; }
A program that instantiates the definition of unexpected for a non-object type, an array type, a specialization of unexpected, or a cv-qualified type is ill-formed.

22.8.3.2 Constructors [expected.un.cons]

template<class Err = E> constexpr explicit unexpected(Err&& e);
Constraints:
  • is_same_v<remove_cvref_t<Err>, unexpected> is false; and
  • is_same_v<remove_cvref_t<Err>, in_place_t> is false; and
  • is_constructible_v<E, Err> is true.
Effects: Direct-non-list-initializes unex with std​::​forward<Err>(e).
Throws: Any exception thrown by the initialization of unex.
template<class... Args> constexpr explicit unexpected(in_place_t, Args&&... args);
Constraints: is_constructible_v<E, Args...> is true.
Effects: Direct-non-list-initializes unex with std​::​forward<Args>(args)....
Throws: Any exception thrown by the initialization of unex.
template<class U, class... Args> constexpr explicit unexpected(in_place_t, initializer_list<U> il, Args&&... args);
Constraints: is_constructible_v<E, initializer_list<U>&, Args...> is true.
Effects: Direct-non-list-initializes unex with il, std​::​forward<Args>(args)....
Throws: Any exception thrown by the initialization of unex.

22.8.3.3 Observers [expected.un.obs]

constexpr const E& error() const & noexcept; constexpr E& error() & noexcept;
Returns: unex.
constexpr E&& error() && noexcept; constexpr const E&& error() const && noexcept;
Returns: std​::​move(unex).

22.8.3.4 Swap [expected.un.swap]

constexpr void swap(unexpected& other) noexcept(is_nothrow_swappable_v<E>);
Mandates: is_swappable_v<E> is true.
Effects: Equivalent to: using std​::​swap; swap(unex, other.unex);
friend constexpr void swap(unexpected& x, unexpected& y) noexcept(noexcept(x.swap(y)));
Constraints: is_swappable_v<E> is true.
Effects: Equivalent to x.swap(y).

22.8.3.5 Equality operator [expected.un.eq]

template<class E2> friend constexpr bool operator==(const unexpected& x, const unexpected<E2>& y);
Mandates: The expression x.error() == y.error() is well-formed and its result is convertible to bool.
Returns: x.error() == y.error().

22.8.4 Class template bad_expected_access [expected.bad]

namespace std { template<class E> class bad_expected_access : public bad_expected_access<void> { public: explicit bad_expected_access(E); const char* what() const noexcept override; E& error() & noexcept; const E& error() const & noexcept; E&& error() && noexcept; const E&& error() const && noexcept; private: E unex; // exposition only }; }
The class template bad_expected_access defines the type of objects thrown as exceptions to report the situation where an attempt is made to access the value of an expected<T, E> object for which has_value() is false.
explicit bad_expected_access(E e);
Effects: Initializes unex with std​::​move(e).
const E& error() const & noexcept; E& error() & noexcept;
Returns: unex.
E&& error() && noexcept; const E&& error() const && noexcept;
Returns: std​::​move(unex).
const char* what() const noexcept override;
Returns: An implementation-defined ntbs.

22.8.5 Class template specialization bad_expected_access<void> [expected.bad.void]

namespace std { template<> class bad_expected_access<void> : public exception { protected: bad_expected_access() noexcept; bad_expected_access(const bad_expected_access&); bad_expected_access(bad_expected_access&&); bad_expected_access& operator=(const bad_expected_access&); bad_expected_access& operator=(bad_expected_access&&); ~bad_expected_access(); public: const char* what() const noexcept override; }; }
const char* what() const noexcept override;
Returns: An implementation-defined ntbs.

22.8.6 Class template expected [expected.expected]

22.8.6.1 General [expected.object.general]

namespace std { template<class T, class E> class expected { public: using value_type = T; using error_type = E; using unexpected_type = unexpected<E>; template<class U> using rebind = expected<U, error_type>; // [expected.object.cons], constructors constexpr expected(); constexpr expected(const expected&); constexpr expected(expected&&) noexcept(see below); template<class U, class G> constexpr explicit(see below) expected(const expected<U, G>&); template<class U, class G> constexpr explicit(see below) expected(expected<U, G>&&); template<class U = T> constexpr explicit(see below) expected(U&& v); template<class G> constexpr explicit(see below) expected(const unexpected<G>&); template<class G> constexpr explicit(see below) expected(unexpected<G>&&); template<class... Args> constexpr explicit expected(in_place_t, Args&&...); template<class U, class... Args> constexpr explicit expected(in_place_t, initializer_list<U>, Args&&...); template<class... Args> constexpr explicit expected(unexpect_t, Args&&...); template<class U, class... Args> constexpr explicit expected(unexpect_t, initializer_list<U>, Args&&...); // [expected.object.dtor], destructor constexpr ~expected(); // [expected.object.assign], assignment constexpr expected& operator=(const expected&); constexpr expected& operator=(expected&&) noexcept(see below); template<class U = T> constexpr expected& operator=(U&&); template<class G> constexpr expected& operator=(const unexpected<G>&); template<class G> constexpr expected& operator=(unexpected<G>&&); template<class... Args> constexpr T& emplace(Args&&...) noexcept; template<class U, class... Args> constexpr T& emplace(initializer_list<U>, Args&&...) noexcept; // [expected.object.swap], swap constexpr void swap(expected&) noexcept(see below); friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y))); // [expected.object.obs], observers constexpr const T* operator->() const noexcept; constexpr T* operator->() noexcept; constexpr const T& operator*() const & noexcept; constexpr T& operator*() & noexcept; constexpr const T&& operator*() const && noexcept; constexpr T&& operator*() && noexcept; constexpr explicit operator bool() const noexcept; constexpr bool has_value() const noexcept; constexpr const T& value() const &; // freestanding-deleted constexpr T& value() &; // freestanding-deleted constexpr const T&& value() const &&; // freestanding-deleted constexpr T&& value() &&; // freestanding-deleted constexpr const E& error() const & noexcept; constexpr E& error() & noexcept; constexpr const E&& error() const && noexcept; constexpr E&& error() && noexcept; template<class U> constexpr T value_or(U&&) const &; template<class U> constexpr T value_or(U&&) &&; template<class G = E> constexpr E error_or(G&&) const &; template<class G = E> constexpr E error_or(G&&) &&; // [expected.object.monadic], monadic operations template<class F> constexpr auto and_then(F&& f) &; template<class F> constexpr auto and_then(F&& f) &&; template<class F> constexpr auto and_then(F&& f) const &; template<class F> constexpr auto and_then(F&& f) const &&; template<class F> constexpr auto or_else(F&& f) &; template<class F> constexpr auto or_else(F&& f) &&; template<class F> constexpr auto or_else(F&& f) const &; template<class F> constexpr auto or_else(F&& f) const &&; template<class F> constexpr auto transform(F&& f) &; template<class F> constexpr auto transform(F&& f) &&; template<class F> constexpr auto transform(F&& f) const &; template<class F> constexpr auto transform(F&& f) const &&; template<class F> constexpr auto transform_error(F&& f) &; template<class F> constexpr auto transform_error(F&& f) &&; template<class F> constexpr auto transform_error(F&& f) const &; template<class F> constexpr auto transform_error(F&& f) const &&; // [expected.object.eq], equality operators template<class T2, class E2> requires (!is_void_v<T2>) friend constexpr bool operator==(const expected& x, const expected<T2, E2>& y); template<class T2> friend constexpr bool operator==(const expected&, const T2&); template<class E2> friend constexpr bool operator==(const expected&, const unexpected<E2>&); private: bool has_val; // exposition only union { T val; // exposition only E unex; // exposition only }; }; }
Any object of type expected<T, E> either contains a value of type T or a value of type E within its own storage.
Implementations are not permitted to use additional storage, such as dynamic memory, to allocate the object of type T or the object of type E.
Member has_val indicates whether the expected<T, E> object contains an object of type T.
A type T is a valid value type for expected, if remove_cv_t<T> is void or a complete non-array object type that is not in_place_t, unexpect_t, or a specialization of unexpected.
A program which instantiates class template expected<T, E> with an argument T that is not a valid value type for expected is ill-formed.
A program that instantiates the definition of the template expected<T, E> with a type for the E parameter that is not a valid template argument for unexpected is ill-formed.
When T is not cv void, it shall meet the Cpp17Destructible requirements (Table 35).
E shall meet the Cpp17Destructible requirements.

22.8.6.2 Constructors [expected.object.cons]

The exposition-only variable template converts-from-any-cvref defined in [optional.ctor] is used by some constructors for expected.
constexpr expected();
Constraints: is_default_constructible_v<T> is true.
Effects: Value-initializes val.
Postconditions: has_value() is true.
Throws: Any exception thrown by the initialization of val.
constexpr expected(const expected& rhs);
Effects: If rhs.has_value() is true, direct-non-list-initializes val with *rhs.
Otherwise, direct-non-list-initializes unex with rhs.error().
Postconditions: rhs.has_value() == this->has_value().
Throws: Any exception thrown by the initialization of val or unex.
Remarks: This constructor is defined as deleted unless
  • is_copy_constructible_v<T> is true and
  • is_copy_constructible_v<E> is true.
This constructor is trivial if
  • is_trivially_copy_constructible_v<T> is true and
  • is_trivially_copy_constructible_v<E> is true.
constexpr expected(expected&& rhs) noexcept(see below);
Constraints:
  • is_move_constructible_v<T> is true and
  • is_move_constructible_v<E> is true.
Effects: If rhs.has_value() is true, direct-non-list-initializes val with std​::​move(*rhs).
Otherwise, direct-non-list-initializes unex with std​::​move(rhs.error()).
Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true.
Throws: Any exception thrown by the initialization of val or unex.
Remarks: The exception specification is equivalent to is_nothrow_move_constructible_v<T> && is_nothrow_move_constructible_v<E>.
This constructor is trivial if
  • is_trivially_move_constructible_v<T> is true and
  • is_trivially_move_constructible_v<E> is true.
template<class U, class G> constexpr explicit(see below) expected(const expected<U, G>& rhs); template<class U, class G> constexpr explicit(see below) expected(expected<U, G>&& rhs);
Let:
  • UF be const U& for the first overload and U for the second overload.
  • GF be const G& for the first overload and G for the second overload.
Constraints:
  • is_constructible_v<T, UF> is true; and
  • is_constructible_v<E, GF> is true; and
  • if T is not cv bool, converts-from-any-cvref<T, expected<U, G>> is false; and
  • is_constructible_v<unexpected<E>, expected<U, G>&> is false; and
  • is_constructible_v<unexpected<E>, expected<U, G>> is false; and
  • is_constructible_v<unexpected<E>, const expected<U, G>&> is false; and
  • is_constructible_v<unexpected<E>, const expected<U, G>> is false.
Effects: If rhs.has_value(), direct-non-list-initializes val with std​::​forward<UF>(*rhs).
Otherwise, direct-non-list-initializes unex with std​::​forward<GF>(rhs.error()).
Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true.
Throws: Any exception thrown by the initialization of val or unex.
Remarks: The expression inside explicit is equivalent to !is_convertible_v<UF, T> || !is_convertible_v<GF, E>.
template<class U = T> constexpr explicit(!is_convertible_v<U, T>) expected(U&& v);
Constraints:
  • is_same_v<remove_cvref_t<U>, in_place_t> is false; and
  • is_same_v<expected, remove_cvref_t<U>> is false; and
  • remove_cvref_t<U> is not a specialization of unexpected; and
  • is_constructible_v<T, U> is true; and
  • if T is cv bool, remove_cvref_t<U> is not a specialization of expected.
Effects: Direct-non-list-initializes val with std​::​forward<U>(v).
Postconditions: has_value() is true.
Throws: Any exception thrown by the initialization of val.
template<class G> constexpr explicit(!is_convertible_v<const G&, E>) expected(const unexpected<G>& e); template<class G> constexpr explicit(!is_convertible_v<G, E>) expected(unexpected<G>&& e);
Let GF be const G& for the first overload and G for the second overload.
Constraints: is_constructible_v<E, GF> is true.
Effects: Direct-non-list-initializes unex with std​::​forward<GF>(e.error()).
Postconditions: has_value() is false.
Throws: Any exception thrown by the initialization of unex.
template<class... Args> constexpr explicit expected(in_place_t, Args&&... args);
Constraints: is_constructible_v<T, Args...> is true.
Effects: Direct-non-list-initializes val with std​::​forward<Args>(args)....
Postconditions: has_value() is true.
Throws: Any exception thrown by the initialization of val.
template<class U, class... Args> constexpr explicit expected(in_place_t, initializer_list<U> il, Args&&... args);
Constraints: is_constructible_v<T, initializer_list<U>&, Args...> is true.
Effects: Direct-non-list-initializes val with il, std​::​forward<Args>(args)....
Postconditions: has_value() is true.
Throws: Any exception thrown by the initialization of val.
template<class... Args> constexpr explicit expected(unexpect_t, Args&&... args);
Constraints: is_constructible_v<E, Args...> is true.
Effects: Direct-non-list-initializes unex with std​::​forward<Args>(args)....
Postconditions: has_value() is false.
Throws: Any exception thrown by the initialization of unex.
template<class U, class... Args> constexpr explicit expected(unexpect_t, initializer_list<U> il, Args&&... args);
Constraints: is_constructible_v<E, initializer_list<U>&, Args...> is true.
Effects: Direct-non-list-initializes unex with il, std​::​forward<Args>(args)....
Postconditions: has_value() is false.
Throws: Any exception thrown by the initialization of unex.

22.8.6.3 Destructor [expected.object.dtor]

constexpr ~expected();
Effects: If has_value() is true, destroys val, otherwise destroys unex.
Remarks: If is_trivially_destructible_v<T> is true, and is_trivially_destructible_v<E> is true, then this destructor is a trivial destructor.

22.8.6.4 Assignment [expected.object.assign]

This subclause makes use of the following exposition-only function template: template<class T, class U, class... Args> constexpr void reinit-expected(T& newval, U& oldval, Args&&... args) { // exposition only if constexpr (is_nothrow_constructible_v<T, Args...>) { destroy_at(addressof(oldval)); construct_at(addressof(newval), std::forward<Args>(args)...); } else if constexpr (is_nothrow_move_constructible_v<T>) { T tmp(std::forward<Args>(args)...); destroy_at(addressof(oldval)); construct_at(addressof(newval), std::move(tmp)); } else { U tmp(std::move(oldval)); destroy_at(addressof(oldval)); try { construct_at(addressof(newval), std::forward<Args>(args)...); } catch (...) { construct_at(addressof(oldval), std::move(tmp)); throw; } } }
constexpr expected& operator=(const expected& rhs);
Effects:
  • If this->has_value() && rhs.has_value() is true, equivalent to val = *rhs.
  • Otherwise, if this->has_value() is true, equivalent to: reinit-expected(unex, val, rhs.error())
  • Otherwise, if rhs.has_value() is true, equivalent to: reinit-expected(val, unex, *rhs)
  • Otherwise, equivalent to unex = rhs.error().
Then, if no exception was thrown, equivalent to: has_val = rhs.has_value(); return *this;
Returns: *this.
Remarks: This operator is defined as deleted unless:
  • is_copy_assignable_v<T> is true and
  • is_copy_constructible_v<T> is true and
  • is_copy_assignable_v<E> is true and
  • is_copy_constructible_v<E> is true and
  • is_nothrow_move_constructible_v<T> || is_nothrow_move_constructible_v<E> is true.
constexpr expected& operator=(expected&& rhs) noexcept(see below);
Constraints:
  • is_move_constructible_v<T> is true and
  • is_move_assignable_v<T> is true and
  • is_move_constructible_v<E> is true and
  • is_move_assignable_v<E> is true and
  • is_nothrow_move_constructible_v<T> || is_nothrow_move_constructible_v<E> is true.
Effects:
  • If this->has_value() && rhs.has_value() is true, equivalent to val = std​::​move(*rhs).
  • Otherwise, if this->has_value() is true, equivalent to: reinit-expected(unex, val, std::move(rhs.error()))
  • Otherwise, if rhs.has_value() is true, equivalent to: reinit-expected(val, unex, std::move(*rhs))
  • Otherwise, equivalent to unex = std​::​move(rhs.error()).
Then, if no exception was thrown, equivalent to: has_val = rhs.has_value(); return *this;
Returns: *this.
Remarks: The exception specification is equivalent to: is_nothrow_move_assignable_v<T> && is_nothrow_move_constructible_v<T> && is_nothrow_move_assignable_v<E> && is_nothrow_move_constructible_v<E>
template<class U = T> constexpr expected& operator=(U&& v);
Constraints:
  • is_same_v<expected, remove_cvref_t<U>> is false; and
  • remove_cvref_t<U> is not a specialization of unexpected; and
  • is_constructible_v<T, U> is true; and
  • is_assignable_v<T&, U> is true; and
  • is_nothrow_constructible_v<T, U> || is_nothrow_move_constructible_v<T> ||
    is_nothrow_move_constructible_v<E>
    is true.
Effects:
  • If has_value() is true, equivalent to: val = std​::​forward<U>(v);
  • Otherwise, equivalent to: reinit-expected(val, unex, std::forward<U>(v)); has_val = true;
Returns: *this.
template<class G> constexpr expected& operator=(const unexpected<G>& e); template<class G> constexpr expected& operator=(unexpected<G>&& e);
Let GF be const G& for the first overload and G for the second overload.
Constraints:
  • is_constructible_v<E, GF> is true; and
  • is_assignable_v<E&, GF> is true; and
  • is_nothrow_constructible_v<E, GF> || is_nothrow_move_constructible_v<T> ||
    is_nothrow_move_constructible_v<E>
    is true.
Effects:
  • If has_value() is true, equivalent to: reinit-expected(unex, val, std::forward<GF>(e.error())); has_val = false;
  • Otherwise, equivalent to: unex = std​::​forward<GF>(e.error());
Returns: *this.
template<class... Args> constexpr T& emplace(Args&&... args) noexcept;
Constraints: is_nothrow_constructible_v<T, Args...> is true.
Effects: Equivalent to: if (has_value()) { destroy_at(addressof(val)); } else { destroy_at(addressof(unex)); has_val = true; } return *construct_at(addressof(val), std::forward<Args>(args)...);
template<class U, class... Args> constexpr T& emplace(initializer_list<U> il, Args&&... args) noexcept;
Constraints: is_nothrow_constructible_v<T, initializer_list<U>&, Args...> is true.
Effects: Equivalent to: if (has_value()) { destroy_at(addressof(val)); } else { destroy_at(addressof(unex)); has_val = true; } return *construct_at(addressof(val), il, std::forward<Args>(args)...);

22.8.6.5 Swap [expected.object.swap]

constexpr void swap(expected& rhs) noexcept(see below);
Constraints:
  • is_swappable_v<T> is true and
  • is_swappable_v<E> is true and
  • is_move_constructible_v<T> && is_move_constructible_v<E> is true, and
  • is_nothrow_move_constructible_v<T> || is_nothrow_move_constructible_v<E> is true.
Effects: See Table 63.
Table 63: swap(expected&) effects [tab:expected.object.swap]
this->has_value()
!this->has_value()
rhs.has_value()
equivalent to: using std​::​swap; swap(val, rhs.val);
calls rhs.swap(*this)
!rhs.has_value()
see below
equivalent to: using std​::​swap; swap(unex, rhs.unex);
For the case where rhs.has_value() is false and this->has_value() is true, equivalent to: if constexpr (is_nothrow_move_constructible_v<E>) { E tmp(std::move(rhs.unex)); destroy_at(addressof(rhs.unex)); try { construct_at(addressof(rhs.val), std::move(val)); destroy_at(addressof(val)); construct_at(addressof(unex), std::move(tmp)); } catch(...) { construct_at(addressof(rhs.unex), std::move(tmp)); throw; } } else { T tmp(std::move(val)); destroy_at(addressof(val)); try { construct_at(addressof(unex), std::move(rhs.unex)); destroy_at(addressof(rhs.unex)); construct_at(addressof(rhs.val), std::move(tmp)); } catch (...) { construct_at(addressof(val), std::move(tmp)); throw; } } has_val = false; rhs.has_val = true;
Throws: Any exception thrown by the expressions in the Effects.
Remarks: The exception specification is equivalent to: is_nothrow_move_constructible_v<T> && is_nothrow_swappable_v<T> && is_nothrow_move_constructible_v<E> && is_nothrow_swappable_v<E>
friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y)));
Effects: Equivalent to x.swap(y).

22.8.6.6 Observers [expected.object.obs]

constexpr const T* operator->() const noexcept; constexpr T* operator->() noexcept;
Preconditions: has_value() is true.
Returns: addressof(val).
constexpr const T& operator*() const & noexcept; constexpr T& operator*() & noexcept;
Preconditions: has_value() is true.
Returns: val.
constexpr T&& operator*() && noexcept; constexpr const T&& operator*() const && noexcept;
Preconditions: has_value() is true.
Returns: std​::​move(val).
constexpr explicit operator bool() const noexcept; constexpr bool has_value() const noexcept;
Returns: has_val.
constexpr const T& value() const &; constexpr T& value() &;
Mandates: is_copy_constructible_v<E> is true.
Returns: val, if has_value() is true.
Throws: bad_expected_access(as_const(error())) if has_value() is false.
constexpr T&& value() &&; constexpr const T&& value() const &&;
Mandates: is_copy_constructible_v<E> is true and is_constructible_v<E, decltype(std​::​
move(error()))>
is true.
Returns: std​::​move(val), if has_value() is true.
Throws: bad_expected_access(std​::​move(error())) if has_value() is false.
constexpr const E& error() const & noexcept; constexpr E& error() & noexcept;
Preconditions: has_value() is false.
Returns: unex.
constexpr E&& error() && noexcept; constexpr const E&& error() const && noexcept;
Preconditions: has_value() is false.
Returns: std​::​move(unex).
template<class U> constexpr T value_or(U&& v) const &;
Mandates: is_copy_constructible_v<T> is true and is_convertible_v<U, T> is true.
Returns: has_value() ? **this : static_cast<T>(std​::​forward<U>(v)).
template<class U> constexpr T value_or(U&& v) &&;
Mandates: is_move_constructible_v<T> is true and is_convertible_v<U, T> is true.
Returns: has_value() ? std​::​move(**this) : static_cast<T>(std​::​forward<U>(v)).
template<class G = E> constexpr E error_or(G&& e) const &;
Mandates: is_copy_constructible_v<E> is true and is_convertible_v<G, E> is true.
Returns: std​::​forward<G>(e) if has_value() is true, error() otherwise.
template<class G = E> constexpr E error_or(G&& e) &&;
Mandates: is_move_constructible_v<E> is true and is_convertible_v<G, E> is true.
Returns: std​::​forward<G>(e) if has_value() is true, std​::​move(error()) otherwise.

22.8.6.7 Monadic operations [expected.object.monadic]

template<class F> constexpr auto and_then(F&& f) &; template<class F> constexpr auto and_then(F&& f) const &;
Let U be remove_cvref_t<invoke_result_t<F, decltype((val))>>.
Constraints: is_constructible_v<E, decltype(error())> is true.
Mandates: U is a specialization of expected and is_same_v<U​::​error_type, E> is true.
Effects: Equivalent to: if (has_value()) return invoke(std::forward<F>(f), val); else return U(unexpect, error());
template<class F> constexpr auto and_then(F&& f) &&; template<class F> constexpr auto and_then(F&& f) const &&;
Let U be remove_cvref_t<invoke_result_t<F, decltype(std​::​move(val))>>.
Constraints: is_constructible_v<E, decltype(std​::​move(error()))> is true.
Mandates: U is a specialization of expected and is_same_v<U​::​error_type, E> is true.
Effects: Equivalent to: if (has_value()) return invoke(std::forward<F>(f), std::move(val)); else return U(unexpect, std::move(error()));
template<class F> constexpr auto or_else(F&& f) &; template<class F> constexpr auto or_else(F&& f) const &;
Let G be remove_cvref_t<invoke_result_t<F, decltype(error())>>.
Constraints: is_constructible_v<T, decltype((val))> is true.
Mandates: G is a specialization of expected and is_same_v<G​::​value_type, T> is true.
Effects: Equivalent to: if (has_value()) return G(in_place, val); else return invoke(std::forward<F>(f), error());
template<class F> constexpr auto or_else(F&& f) &&; template<class F> constexpr auto or_else(F&& f) const &&;
Let G be remove_cvref_t<invoke_result_t<F, decltype(std​::​move(error()))>>.
Constraints: is_constructible_v<T, decltype(std​::​move(val))> is true.
Mandates: G is a specialization of expected and is_same_v<G​::​value_type, T> is true.
Effects: Equivalent to: if (has_value()) return G(in_place, std::move(val)); else return invoke(std::forward<F>(f), std::move(error()));
template<class F> constexpr auto transform(F&& f) &; template<class F> constexpr auto transform(F&& f) const &;
Let U be remove_cv_t<invoke_result_t<F, decltype((val))>>.
Constraints: is_constructible_v<E, decltype(error())> is true.
Mandates: U is a valid value type for expected.
If is_void_v<U> is false, the declaration U u(invoke(std::forward<F>(f), val)); is well-formed.
Effects:
  • If has_value() is false, returns expected<U, E>(unexpect, error()).
  • Otherwise, if is_void_v<U> is false, returns an expected<U, E> object whose has_val member is true and val member is direct-non-list-initialized with invoke(std​::​forward<F>(f), val).
  • Otherwise, evaluates invoke(std​::​forward<F>(f), val) and then returns expected<U, E>().
template<class F> constexpr auto transform(F&& f) &&; template<class F> constexpr auto transform(F&& f) const &&;
Let U be remove_cv_t<invoke_result_t<F, decltype(std​::​move(val))>>.
Constraints: is_constructible_v<E, decltype(std​::​move(error()))> is true.
Mandates: U is a valid value type for expected.
If is_void_v<U> is false, the declaration U u(invoke(std::forward<F>(f), std::move(val))); is well-formed.
Effects:
  • If has_value() is false, returns expected<U, E>(unexpect, std​::​move(error())).
  • Otherwise, if is_void_v<U> is false, returns an expected<U, E> object whose has_val member is true and val member is direct-non-list-initialized with invoke(std​::​forward<F>(f), std​::​move(val)).
  • Otherwise, evaluates invoke(std​::​forward<F>(f), std​::​move(val)) and then returns expected<U, E>().
template<class F> constexpr auto transform_error(F&& f) &; template<class F> constexpr auto transform_error(F&& f) const &;
Let G be remove_cv_t<invoke_result_t<F, decltype(error())>>.
Constraints: is_constructible_v<T, decltype((val))> is true.
Mandates: G is a valid template argument for unexpected ([expected.un.general]) and the declaration G g(invoke(std::forward<F>(f), error())); is well-formed.
Returns: If has_value() is true, expected<T, G>(in_place, val); otherwise, an expected<T, G> object whose has_val member is false and unex member is direct-non-list-initialized with invoke(std​::​forward<F>(f), error()).
template<class F> constexpr auto transform_error(F&& f) &&; template<class F> constexpr auto transform_error(F&& f) const &&;
Let G be remove_cv_t<invoke_result_t<F, decltype(std​::​move(error()))>>.
Constraints: is_constructible_v<T, decltype(std​::​move(val))> is true.
Mandates: G is a valid template argument for unexpected ([expected.un.general]) and the declaration G g(invoke(std::forward<F>(f), std::move(error()))); is well-formed.
Returns: If has_value() is true, expected<T, G>(in_place, std​::​move(val)); otherwise, an expected<T, G> object whose has_val member is false and unex member is direct-non-list-initialized with invoke(std​::​forward<F>(f), std​::​move(error())).

22.8.6.8 Equality operators [expected.object.eq]

template<class T2, class E2> requires (!is_void_v<T2>) friend constexpr bool operator==(const expected& x, const expected<T2, E2>& y);
Mandates: The expressions *x == *y and x.error() == y.error() are well-formed and their results are convertible to bool.
Returns: If x.has_value() does not equal y.has_value(), false; otherwise if x.has_value() is true, *x == *y; otherwise x.error() == y.error().
template<class T2> friend constexpr bool operator==(const expected& x, const T2& v);
Mandates: The expression *x == v is well-formed and its result is convertible to bool.
[Note 1: 
T need not be Cpp17EqualityComparable.
— end note]
Returns: x.has_value() && static_cast<bool>(*x == v).
template<class E2> friend constexpr bool operator==(const expected& x, const unexpected<E2>& e);
Mandates: The expression x.error() == e.error() is well-formed and its result is convertible to bool.
Returns: !x.has_value() && static_cast<bool>(x.error() == e.error()).

22.8.7 Partial specialization of expected for void types [expected.void]

22.8.7.1 General [expected.void.general]

template<class T, class E> requires is_void_v<T> class expected<T, E> { public: using value_type = T; using error_type = E; using unexpected_type = unexpected<E>; template<class U> using rebind = expected<U, error_type>; // [expected.void.cons], constructors constexpr expected() noexcept; constexpr expected(const expected&); constexpr expected(expected&&) noexcept(see below); template<class U, class G> constexpr explicit(see below) expected(const expected<U, G>&); template<class U, class G> constexpr explicit(see below) expected(expected<U, G>&&); template<class G> constexpr explicit(see below) expected(const unexpected<G>&); template<class G> constexpr explicit(see below) expected(unexpected<G>&&); constexpr explicit expected(in_place_t) noexcept; template<class... Args> constexpr explicit expected(unexpect_t, Args&&...); template<class U, class... Args> constexpr explicit expected(unexpect_t, initializer_list<U>, Args&&...); // [expected.void.dtor], destructor constexpr ~expected(); // [expected.void.assign], assignment constexpr expected& operator=(const expected&); constexpr expected& operator=(expected&&) noexcept(see below); template<class G> constexpr expected& operator=(const unexpected<G>&); template<class G> constexpr expected& operator=(unexpected<G>&&); constexpr void emplace() noexcept; // [expected.void.swap], swap constexpr void swap(expected&) noexcept(see below); friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y))); // [expected.void.obs], observers constexpr explicit operator bool() const noexcept; constexpr bool has_value() const noexcept; constexpr void operator*() const noexcept; constexpr void value() const &; // freestanding-deleted constexpr void value() &&; // freestanding-deleted constexpr const E& error() const & noexcept; constexpr E& error() & noexcept; constexpr const E&& error() const && noexcept; constexpr E&& error() && noexcept; template<class G = E> constexpr E error_or(G&&) const &; template<class G = E> constexpr E error_or(G&&) &&; // [expected.void.monadic], monadic operations template<class F> constexpr auto and_then(F&& f) &; template<class F> constexpr auto and_then(F&& f) &&; template<class F> constexpr auto and_then(F&& f) const &; template<class F> constexpr auto and_then(F&& f) const &&; template<class F> constexpr auto or_else(F&& f) &; template<class F> constexpr auto or_else(F&& f) &&; template<class F> constexpr auto or_else(F&& f) const &; template<class F> constexpr auto or_else(F&& f) const &&; template<class F> constexpr auto transform(F&& f) &; template<class F> constexpr auto transform(F&& f) &&; template<class F> constexpr auto transform(F&& f) const &; template<class F> constexpr auto transform(F&& f) const &&; template<class F> constexpr auto transform_error(F&& f) &; template<class F> constexpr auto transform_error(F&& f) &&; template<class F> constexpr auto transform_error(F&& f) const &; template<class F> constexpr auto transform_error(F&& f) const &&; // [expected.void.eq], equality operators template<class T2, class E2> requires is_void_v<T2> friend constexpr bool operator==(const expected& x, const expected<T2, E2>& y); template<class E2> friend constexpr bool operator==(const expected&, const unexpected<E2>&); private: bool has_val; // exposition only union { E unex; // exposition only }; };
Any object of type expected<T, E> either represents a value of type T, or contains a value of type E within its own storage.
Implementations are not permitted to use additional storage, such as dynamic memory, to allocate the object of type E.
Member has_val indicates whether the expected<T, E> object represents a value of type T.
A program that instantiates the definition of the template expected<T, E> with a type for the E parameter that is not a valid template argument for unexpected is ill-formed.
E shall meet the requirements of Cpp17Destructible (Table 35).

22.8.7.2 Constructors [expected.void.cons]

constexpr expected() noexcept;
Postconditions: has_value() is true.
constexpr expected(const expected& rhs);
Effects: If rhs.has_value() is false, direct-non-list-initializes unex with rhs.error().
Postconditions: rhs.has_value() == this->has_value().
Throws: Any exception thrown by the initialization of unex.
Remarks: This constructor is defined as deleted unless is_copy_constructible_v<E> is true.
This constructor is trivial if is_trivially_copy_constructible_v<E> is true.
constexpr expected(expected&& rhs) noexcept(is_nothrow_move_constructible_v<E>);
Constraints: is_move_constructible_v<E> is true.
Effects: If rhs.has_value() is false, direct-non-list-initializes unex with std​::​move(rhs.error()).
Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true.
Throws: Any exception thrown by the initialization of unex.
Remarks: This constructor is trivial if is_trivially_move_constructible_v<E> is true.
template<class U, class G> constexpr explicit(!is_convertible_v<const G&, E>) expected(const expected<U, G>& rhs); template<class U, class G> constexpr explicit(!is_convertible_v<G, E>) expected(expected<U, G>&& rhs);
Let GF be const G& for the first overload and G for the second overload.
Constraints:
  • is_void_v<U> is true; and
  • is_constructible_v<E, GF> is true; and
  • is_constructible_v<unexpected<E>, expected<U, G>&> is false; and
  • is_constructible_v<unexpected<E>, expected<U, G>> is false; and
  • is_constructible_v<unexpected<E>, const expected<U, G>&> is false; and
  • is_constructible_v<unexpected<E>, const expected<U, G>> is false.
Effects: If rhs.has_value() is false, direct-non-list-initializes unex with std​::​forward<GF>(rhs.error()).
Postconditions: rhs.has_value() is unchanged; rhs.has_value() == this->has_value() is true.
Throws: Any exception thrown by the initialization of unex.
template<class G> constexpr explicit(!is_convertible_v<const G&, E>) expected(const unexpected<G>& e); template<class G> constexpr explicit(!is_convertible_v<G, E>) expected(unexpected<G>&& e);
Let GF be const G& for the first overload and G for the second overload.
Constraints: is_constructible_v<E, GF> is true.
Effects: Direct-non-list-initializes unex with std​::​forward<GF>(e.error()).
Postconditions: has_value() is false.
Throws: Any exception thrown by the initialization of unex.
constexpr explicit expected(in_place_t) noexcept;
Postconditions: has_value() is true.
template<class... Args> constexpr explicit expected(unexpect_t, Args&&... args);
Constraints: is_constructible_v<E, Args...> is true.
Effects: Direct-non-list-initializes unex with std​::​forward<Args>(args)....
Postconditions: has_value() is false.
Throws: Any exception thrown by the initialization of unex.
template<class U, class... Args> constexpr explicit expected(unexpect_t, initializer_list<U> il, Args&&... args);
Constraints: is_constructible_v<E, initializer_list<U>&, Args...> is true.
Effects: Direct-non-list-initializes unex with il, std​::​forward<Args>(args)....
Postconditions: has_value() is false.
Throws: Any exception thrown by the initialization of unex.

22.8.7.3 Destructor [expected.void.dtor]

constexpr ~expected();
Effects: If has_value() is false, destroys unex.
Remarks: If is_trivially_destructible_v<E> is true, then this destructor is a trivial destructor.

22.8.7.4 Assignment [expected.void.assign]

constexpr expected& operator=(const expected& rhs);
Effects:
  • If this->has_value() && rhs.has_value() is true, no effects.
  • Otherwise, if this->has_value() is true, equivalent to: construct_at(addressof(unex), rhs.unex); has_val = false;
  • Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true.
  • Otherwise, equivalent to unex = rhs.error().
Returns: *this.
Remarks: This operator is defined as deleted unless is_copy_assignable_v<E> is true and is_copy_constructible_v<E> is true.
constexpr expected& operator=(expected&& rhs) noexcept(see below);
Effects:
  • If this->has_value() && rhs.has_value() is true, no effects.
  • Otherwise, if this->has_value() is true, equivalent to: construct_at(addressof(unex), std::move(rhs.unex)); has_val = false;
  • Otherwise, if rhs.has_value() is true, destroys unex and sets has_val to true.
  • Otherwise, equivalent to unex = std​::​move(rhs.error()).
Returns: *this.
Remarks: The exception specification is equivalent to is_nothrow_move_constructible_v<E> && is_nothrow_move_assignable_v<E>.
This operator is defined as deleted unless is_move_constructible_v<E> is true and is_move_assignable_v<E> is true.
template<class G> constexpr expected& operator=(const unexpected<G>& e); template<class G> constexpr expected& operator=(unexpected<G>&& e);
Let GF be const G& for the first overload and G for the second overload.
Constraints: is_constructible_v<E, GF> is true and is_assignable_v<E&, GF> is true.
Effects:
  • If has_value() is true, equivalent to: construct_at(addressof(unex), std::forward<GF>(e.error())); has_val = false;
  • Otherwise, equivalent to: unex = std​::​forward<GF>(e.error());
Returns: *this.
constexpr void emplace() noexcept;
Effects: If has_value() is false, destroys unex and sets has_val to true.

22.8.7.5 Swap [expected.void.swap]

constexpr void swap(expected& rhs) noexcept(see below);
Constraints: is_swappable_v<E> is true and is_move_constructible_v<E> is true.
Effects: See Table 64.
Table 64: swap(expected&) effects [tab:expected.void.swap]
this->has_value()
!this->has_value()
rhs.has_value()
no effects
calls rhs.swap(*this)
!rhs.has_value()
see below
equivalent to: using std​::​swap; swap(unex, rhs.unex);
For the case where rhs.has_value() is false and this->has_value() is true, equivalent to: construct_at(addressof(unex), std::move(rhs.unex)); destroy_at(addressof(rhs.unex)); has_val = false; rhs.has_val = true;
Throws: Any exception thrown by the expressions in the Effects.
Remarks: The exception specification is equivalent to is_nothrow_move_constructible_v<E> && is_nothrow_swappable_v<E>.
friend constexpr void swap(expected& x, expected& y) noexcept(noexcept(x.swap(y)));
Effects: Equivalent to x.swap(y).

22.8.7.6 Observers [expected.void.obs]

constexpr explicit operator bool() const noexcept; constexpr bool has_value() const noexcept;
Returns: has_val.
constexpr void operator*() const noexcept;
Preconditions: has_value() is true.
constexpr void value() const &;
Mandates: is_copy_constructible_v<E> is true.
Throws: bad_expected_access(error()) if has_value() is false.
constexpr void value() &&;
Mandates: is_copy_constructible_v<E> is true and is_move_constructible_v<E> is true.
Throws: bad_expected_access(std​::​move(error())) if has_value() is false.
constexpr const E& error() const & noexcept; constexpr E& error() & noexcept;
Preconditions: has_value() is false.
Returns: unex.
constexpr E&& error() && noexcept; constexpr const E&& error() const && noexcept;
Preconditions: has_value() is false.
Returns: std​::​move(unex).
template<class G = E> constexpr E error_or(G&& e) const &;
Mandates: is_copy_constructible_v<E> is true and is_convertible_v<G, E> is true.
Returns: std​::​forward<G>(e) if has_value() is true, error() otherwise.
template<class G = E> constexpr E error_or(G&& e) &&;
Mandates: is_move_constructible_v<E> is true and is_convertible_v<G, E> is true.
Returns: std​::​forward<G>(e) if has_value() is true, std​::​move(error()) otherwise.

22.8.7.7 Monadic operations [expected.void.monadic]

template<class F> constexpr auto and_then(F&& f) &; template<class F> constexpr auto and_then(F&& f) const &;
Let U be remove_cvref_t<invoke_result_t<F>>.
Constraints: is_constructible_v<E, decltype(error())>> is true.
Mandates: U is a specialization of expected and is_same_v<U​::​error_type, E> is true.
Effects: Equivalent to: if (has_value()) return invoke(std::forward<F>(f)); else return U(unexpect, error());
template<class F> constexpr auto and_then(F&& f) &&; template<class F> constexpr auto and_then(F&& f) const &&;
Let U be remove_cvref_t<invoke_result_t<F>>.
Constraints: is_constructible_v<E, decltype(std​::​move(error()))> is true.
Mandates: U is a specialization of expected and is_same_v<U​::​error_type, E> is true.
Effects: Equivalent to: if (has_value()) return invoke(std::forward<F>(f)); else return U(unexpect, std::move(error()));
template<class F> constexpr auto or_else(F&& f) &; template<class F> constexpr auto or_else(F&& f) const &;
Let G be remove_cvref_t<invoke_result_t<F, decltype(error())>>.
Mandates: G is a specialization of expected and is_same_v<G​::​value_type, T> is true.
Effects: Equivalent to: if (has_value()) return G(); else return invoke(std::forward<F>(f), error());
template<class F> constexpr auto or_else(F&& f) &&; template<class F> constexpr auto or_else(F&& f) const &&;
Let G be remove_cvref_t<invoke_result_t<F, decltype(std​::​move(error()))>>.
Mandates: G is a specialization of expected and is_same_v<G​::​value_type, T> is true.
Effects: Equivalent to: if (has_value()) return G(); else return invoke(std::forward<F>(f), std::move(error()));
template<class F> constexpr auto transform(F&& f) &; template<class F> constexpr auto transform(F&& f) const &;
Let U be remove_cv_t<invoke_result_t<F>>.
Constraints: is_constructible_v<E, decltype(error())> is true.
Mandates: U is a valid value type for expected.
If is_void_v<U> is false, the declaration U u(invoke(std::forward<F>(f))); is well-formed.
Effects:
  • If has_value() is false, returns expected<U, E>(unexpect, error()).
  • Otherwise, if is_void_v<U> is false, returns an expected<U, E> object whose has_val member is true and val member is direct-non-list-initialized with invoke(std​::​forward<F>(f)).
  • Otherwise, evaluates invoke(std​::​forward<F>(f)) and then returns expected<U, E>().
template<class F> constexpr auto transform(F&& f) &&; template<class F> constexpr auto transform(F&& f) const &&;
Let U be remove_cv_t<invoke_result_t<F>>.
Constraints: is_constructible_v<E, decltype(std​::​move(error()))> is true.
Mandates: U is a valid value type for expected.
If is_void_v<U> is false, the declaration U u(invoke(std::forward<F>(f))); is well-formed.
Effects:
  • If has_value() is false, returns expected<U, E>(unexpect, std​::​move(error())).
  • Otherwise, if is_void_v<U> is false, returns an expected<U, E> object whose has_val member is true and val member is direct-non-list-initialized with invoke(std​::​forward<F>(f)).
  • Otherwise, evaluates invoke(std​::​forward<F>(f)) and then returns expected<U, E>().
template<class F> constexpr auto transform_error(F&& f) &; template<class F> constexpr auto transform_error(F&& f) const &;
Let G be remove_cv_t<invoke_result_t<F, decltype(error())>>.
Mandates: G is a valid template argument for unexpected ([expected.un.general]) and the declaration G g(invoke(std::forward<F>(f), error())); is well-formed.
Returns: If has_value() is true, expected<T, G>(); otherwise, an expected<T, G> object whose has_val member is false and unex member is direct-non-list-initialized with invoke(std​::​forward<F>(f), error()).
template<class F> constexpr auto transform_error(F&& f) &&; template<class F> constexpr auto transform_error(F&& f) const &&;
Let G be remove_cv_t<invoke_result_t<F, decltype(std​::​move(error()))>>.
Mandates: G is a valid template argument for unexpected ([expected.un.general]) and the declaration G g(invoke(std::forward<F>(f), std::move(error()))); is well-formed.
Returns: If has_value() is true, expected<T, G>(); otherwise, an expected<T, G> object whose has_val member is false and unex member is direct-non-list-initialized with invoke(std​::​forward<F>(f), std​::​move(error())).

22.8.7.8 Equality operators [expected.void.eq]

template<class T2, class E2> requires is_void_v<T2> friend constexpr bool operator==(const expected& x, const expected<T2, E2>& y);
Mandates: The expression x.error() == y.error() is well-formed and its result is convertible to bool.
Returns: If x.has_value() does not equal y.has_value(), false; otherwise x.has_value() || static_cast<bool>(x.error() == y.error()).
template<class E2> friend constexpr bool operator==(const expected& x, const unexpected<E2>& e);
Mandates: The expression x.error() == e.error() is well-formed and its result is convertible to bool.
Returns: !x.has_value() && static_cast<bool>(x.error() == e.error()).