This paper revises [P0323r4] by applying feedback obtained from LEWG and EWG. The previous paper contains motivation, design rationale, implementability information, sample usage, history, alternative designs and related types. This update only contains wording and open questions because its purpose is twofold:
- 
     Present appropriate wording for inclusion in the Library Fundamentals TS v3. 
- 
     List open questions which the TS should aim to answer. 
1. Wording
Below, substitute the � character with a number or name the editor finds
appropriate for the sub-section.
1.1. �.� Unexpected objects [unexpected]
1.2. �.�.1 General [unexpected.general]
This subclause describes class template unexpected that
represents unexpected objects.
1.3. �.�.2 Header <experimental/unexpected> synopsis [unexpected.synop]
namespace std { namespace experimental { inline namespace fundamentals_v3 { // �.�.3, Unexpected object type template <class E> class unexpected; // �.�.4, Unexpected equality operators template <class E1, class E2> constexpr bool operator==(const unexpected<E1>&, const unexpected<E2>&); template <class E1, class E2> constexpr bool operator!=(const unexpected<E1>&, const unexpected<E2>&); // �.�.5, Specialized algorithms void swap(unexpected& x, unexpected& y) noexcept(noexcept(x.swap(y)));; }}}
A program that necessitates the instantiation of template unexpected for a
non-object type or an object type cv-qualified is ill-formed.
1.4. �.�.3 Unexpected object type [unexpected.object]
template <class E> class unexpected { public: unexpected() = delete; constexpr unexpected(const unexpected&) = default; constexpr unexpected(unexpected&&) = default; constexpr unexpected& operator=(const unexpected&) = default; constexpr unexpected& operator=(unexpected&&) = default; template <class Err> constexpr explicit unexpected(Err&&); template <class Err> constexpr EXPLICIT unexpected(const unexpected<Err>&); template <class Err> constexpr EXPLICIT unexpected(unexpected<Err>&&); constexpr const E& value() const& noexcept; constexpr E& value() & noexcept; constexpr const E&& value() const&& noexcept; constexpr E&& value() && noexcept; private: E val; // exposition only };
template <class Err> constexpr explicit unexpected(Err&& e);
Effects: Initializes val as if direct-non-list-initializing an
object of type E with the expression std::forward<Err>(e).
Remark: This constructor participates in overload resolution if and only if std::is_constructible_v<E, Err&&>
template <class Err> constexpr EXPLICIT unexpected(const unexpected<Err>& e);
Effects: Initializes val as if direct-non-list-initializing an
object of type E with the expression e.val.
Remarks: This constructor participates in overload resolution if and only if std::is_constructible_v<E, Err>. This constructor is explicit if and only if std::is_convertible_v<Err, E> is false.
template <class Err> constexpr EXPLICIT unexpected(unexpected<Err> && e);
Effects: Initializes val as if direct-non-list-initializing an
object of type E with the expression std::move(e.val).
Remarks: This constructor participates in overload resolution if and only if std::is_constructible_v<E, Err&&>. This constructor is explicit if and only if std::is_convertible_v<Err&&, E> is false
constexpr const E& value() const &; constexpr E& value() &;
Returns: val.
constexpr E&& value() &&; constexpr E const&& value() const&&;
Returns: std::move(val).
1.5. �.�.4 Unexpected equality operators [unexpected.relational_op]
template <class E, class G> constexpr bool operator==(const unexpected<E>& x, const unexpected<G>& y);
Effects: Equivalent to return x.value() == y.value().
template <class E, class G> constexpr bool operator!=(const unexpected<E>& x, const unexpected<G>& y);
Effects: Equivalent to return x.value() != y.value().
1.6. �.� Expected objects [expected]
1.7. �.�.1 In general [expected.general]
This subclause describes class template expected that represents expected
objects. An expected<T, E> object holds an object of type T or 
an object of type unexpected<E> and manages the lifetime of the contained
object.
1.8. �.�.2 Header <experimental/expected> synopsis [expected.synop]
namespace std { namespace experimental { inline namespace fundamentals_v3 { // �.�.4, Expected for object types template <class T, class E> class expected; // �.�.5, unexpect tag struct unexpect_t { explicit unexpect_t() = default; }; inline constexpr unexpect_t unexpect{}; // �.�.6, class bad_expected_access template <class E> class bad_expected_access; // �.�.7, Specialization for void template <> class bad_expected_access<void>; // �.�.8, Expected equality operators template <class T1, class E1, class T2, class E2> constexpr bool operator==(const expected<T1, E1>& x, const expected<T2, E2>& y); template <class T1, class E1, class T2, class E2> constexpr bool operator!=(const expected<T1, E1>& x, const expected<T2, E2>& y); // �.�.9, Comparison with T template <class T, class E, class U> constexpr bool operator==(const expected<T, E>&, const U&); template <class U, class T, class E> constexpr bool operator==(const U&, const expected<T, E>&); template <class T, class E, class U> constexpr bool operator!=(const expected<T, E>&, const U&); template <class U, class T, class E> constexpr bool operator!=(const U&, const expected<T, E>&); // �.�.10, Comparison with unexpected<E> template <class T, class E, class G> constexpr bool operator==(const expected<T, E>&, const unexpected<G>&); template <class G, class T, class E> constexpr bool operator==(const unexpected<G>&, const expected<T, E>&); template <class T, class E, class G> constexpr bool operator!=(const expected<T, E>&, const unexpected<G>&); template <class G, class T, class E> constexpr bool operator!=(const unexpected<G>&, const expected<T, E>&); // �.�.11, Specialized algorithms template <class T, class E> void swap(expected<T, E>&, expected<T, E>&) noexcept(see below); }}}
A program that necessitates the instantiation of template expected<T, E> for a reference type or for possibly cv-qualified types in_place_t, unexpect_t or unexpected<E> for the T parameter or 
for a reference type E or for possibly cv-qualified void type for the E parameter
is ill-formed.
1.9. �.�.3 Definitions [expected.defs]
An instance of expected<T, E> is said to be valued if it contains a object of
type T. An instance of expected<T, E> is said to be unexpected if it
contains an object of type unexpected<E>.
1.10. �.�.4 expected for object types [expected.object]
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>; // �.�.4.1, constructors constexpr expected(); constexpr expected(const expected&); constexpr expected(expected&&) noexcept(see below); template <class U, class G> EXPLICIT constexpr expected(const expected<U, G>&); template <class U, class G> EXPLICIT constexpr expected(expected<U, G>&&); template <class U = T> EXPLICIT constexpr expected(U&& v); 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 G = E> constexpr expected(const unexpected<G>&); template <class G = E> constexpr expected(unexpected<G> &&); template <class... Args> constexpr explicit expected(unexpect_t, Args&&...); template <class U, class... Args> constexpr explicit expected(unexpect_t, initializer_list<U>, Args&&...); // �.�.4.2, destructor ~expected(); // �.�.4.3, assignment expected& operator=(const expected&); expected& operator=(expected&&) noexcept(see below); template <class U = T> expected& operator=(U&&); template <class G = E> expected& operator=(const unexpected<G>&); template <class G = E> expected& operator=(unexpected<G>&&); template <class... Args> void emplace(Args&&...); template <class U, class... Args> void emplace(initializer_list<U>, Args&&...); // �.�.4.4, swap void swap(expected&) noexcept(see below); // �.�.4.5, observers constexpr const T* operator ->() const; constexpr T* operator ->(); constexpr const T& operator *() const&; constexpr T& operator *() &; constexpr const T&& operator *() const &&; constexpr T&& operator *() &&; constexpr explicit operator bool() const noexcept; constexpr bool has_value() const noexcept; constexpr const T& value() const&; constexpr T& value() &; constexpr const T&& value() const &&; constexpr T&& value() &&; constexpr const E& error() const&; constexpr E& error() &; constexpr const E&& error() const &&; constexpr E&& error() &&; template <class U> constexpr T value_or(U&&) const&; template <class U> constexpr T value_or(U&&) &&; private: bool has_val; // exposition only union { value_type val; // exposition only unexpected_type unexpect; // exposition only }; };
Any instance of expected<T, E> at any given time either contains a value of
type T or a value of type unexpected<E> within their 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 unexpected<E>.
These objects shall be allocated in a region of the expected<T, E> storage
suitably aligned for the types T and unexpected<E>. Members has_val, val and unexpect are provided for exposition only. has_val indicates whether the
object T has been initialized (and not yet destroyed) or an object of type unexpected<E>has been initialized (and not yet destroyed).
T shall be void or shall be an object type and shall satisfy the requirements
of Destructible (Table 27).
E shall be object type and shall satisfy the requirements of Destructible (Table 27).
1.11. �.�.4.1 Constructors [expected.object.ctor]
constexpr expected();
Effects: Value-initializes the contained object as if direct-non-list-initializing an
object of type T with the expression T{} (if T is not void).
Postconditions: bool(*this).
Throws: Any exception thrown by the operations specified in the effect clause.
Remarks: If value-initialization of T is a constexpr constructor or T is void this constructor shall be constexpr. This constructor shall be defined as
deleted unless is_default_constructible_v<T> or T is void.
constexpr expected(const expected& rhs);
Effects: If bool(rhs), initializes val as if
direct-non-list-initializing an object of type T with the expression *rhs (if T is not void).
If !bool(rhs), initializes val as if
direct-non-list-initializing an object of type unexpected<E> with the
expression unexpected(rhs.error()).
Postconditions: bool(rhs) == bool(*this).
Throws: Any exception thrown by operations specified in the effect clause.
Remarks: This constructor shall be defined as deleted unless is_copy_constructible_v<T> or T is void and is_copy_constructible_v<E>. If is_trivially_copy_constructible_v<T> is true or T is void and is_trivially_copy_constructible_v<E> is true,
this constructor shall be a constexpr constructor.
constexpr expected(expected && rhs) noexcept(see below);
Effects: If bool(rhs), initializes val as if
direct-non-list-initializing an object of type T with the expression std::move(*rhs) (if T is not void).
If !bool(rhs), initializes val as if
direct-non-list-initializing an object of type unexpected<E> with the
expression unexpected(std::move(rhs.error())).
bool(rhs) is unchanged.
Postconditions: bool(rhs) == bool(*this).
Throws: Any exception thrown by operations specified in the effect clause.
Remarks: The expression inside noexcept is equivalent to: is_nothrow_move_constructible_v<T> or Tis void and is_nothrow_move_constructible_v<E>. This constructor shall not participate in
overload resolution unless is_move_constructible_v<T> and is_move_constructible_v<E>. If is_trivially_move_constructible_v<T> is true or T is void and is_trivially_move_constructible_v<E> is true,
this constructor shall be a constexpr constructor.
template <class U, class G> EXPLICIT constexpr expected(const expected<U, G>& rhs);
Effects: If bool(rhs), initializes val as if
direct-non-list-initializing an object of type T with the expression *rhs (if T is not void).
If !bool(rhs) initializes unexpect as if
direct-non-list-initializing an object of type unexpected<E> with the
expression unexpected(rhs.error()).
Postconditions: bool(rhs) == bool(*this).
Throws: Any exception thrown by operations specified in the effect clause.
Remarks: This constructor shall not participate in overload resolution unless: T and U are void or
- 
     is_constructible_v<T, const U&>istrue,
- 
     is_constructible_v<E, const G&>istrue,
- 
     is_constructible_v<T, expected<U, G>&>isfalse,
- 
     is_constructible_v<T, expected<U, G>&&>isfalse,
- 
     is_constructible_v<T, const expected<U, G>&>isfalse,
- 
     is_constructible_v<T, const expected<U, G>&&>isfalse,
- 
     is_convertible_v<expected<U, G>&, T>isfalse,
- 
     is_convertible_v<expected<U, G>&&, T>isfalse,
- 
     is_convertible_v<const expected<U, G>&, T>isfalseand
- 
     is_convertible_v<const expected<U, G>&&, T>isfalse.
The constructor is explicit if and only if T is not void and is_convertible_v<U const&, T> is false or is_convertible_v<const G&, E> is false.
template <class U, class G> EXPLICIT constexpr expected(expected<U, G>&& rhs);
Effects: If bool(rhs) initializes val as if
direct-non-list-initializing an object of type T with the expression std::move(*rhs) or nothing if T is void.
If !bool(rhs), initializes unexpect as if
direct-non-list-initializing an object of type unexpected<E> with the
expression unexpected(std::move(rhs.error())).
bool(rhs) is unchanged.
Postconditions: bool(rhs) == bool(*this).
Throws: Any exception thrown by operations specified in the effect clause.
Remarks: This constructor shall not participate in overload resolution unless: T and U are void or
- 
     is_constructible_v<T, U>istrue,
- 
     is_constructible_v<E, G>istrue,
- 
     is_constructible_v<T, expected<U, G>&>isfalse,
- 
     is_constructible_v<T, expected<U, G>&&>isfalse,
- 
     is_constructible_v<T, const expected<U, G>&>isfalse,
- 
     is_constructible_v<T, const expected<U, G>&&>isfalse,
- 
     is_convertible_v<expected<U, G>&, T>isfalse,
- 
     is_convertible_v<expected<U, G>&&, T>isfalse,
- 
     is_convertible_v<const expected<U, G>&, T>isfalse, and
- 
     is_convertible_v<const expected<U, G>&&, T>isfalse.
The constructor is explicit if and only if is_convertible_v<U, T> is false or is_convertible_v<G, E> is false.
template <class U = T> EXPLICIT constexpr expected(U&& v);
Effects: Initializes val as if direct-non-list-initializing an
object of type T with the expression std::forward<U>(v).
Postconditions: bool(*this) .
Throws: Any exception thrown by operations specified in the effect clause.
Remarks: If T's selected constructor is a constexpr constructor, this
constructor shall be a constexpr constructor. This constructor shall not
participate in overload resolution unless T is not void and is_constructible_v<T, U&&> is true, is_same_v<remove_cvref_t<U>, in_place_t> is false, is_same_v<expected<T, E>, remove_cvref_t<U>> is false, and is_same_v<unexpected<E>, remove_cvref_t<U>> is false. The constructor is explicit if
and only if is_convertible_v<U&&, T> is false.
template <class... Args> constexpr explicit expected(in_place_t, Args&&... args);
Effects: Initializes val as if direct-non-list-initializing an
object of type T with the arguments std::forward<Args>(args)... if T is not void.
Postconditions: bool(*this) .
Throws: Any exception thrown by operations specified in the effect clause.
Remarks: If T's constructor selected for the initialization is a constexpr
constructor, this constructor shall be a constexpr constructor. This
constructor shall not participate in overload resolution unless T is void and sizeof...(Args) == 0 or T is not void and is_constructible_v<T, Args...>.
template <class U, class... Args> constexpr explicit expected(in_place_t, initializer_list<U> il, Args&&... args);
Effects: Initializes val as if direct-non-list-initializing an
object of type T with the arguments il, std::forward<Args>(args)....
Postconditions: bool(*this) .
Throws: Any exception thrown by the operations specified in the effect clause.
Remarks: If T's constructor selected for the initialization is a constexpr
constructor, this constructor shall be a constexpr constructor. This
constructor shall not participate in overload resolution unless T is not void and is_constructible_v<T, initializer_list<U>&, Args...>.
template <class G = E> EXPLICIT constexpr expected(const unexpected<G>& e);
Effects: Initializes unexpect as if direct-non-list-initializing
an object of type unexpected<E> with the expression e.
Postconditions: !bool(*this).
Throws: Any exception thrown by the operations specified in the effect clause.
Remark: If unexpected<E>'s selected constructor is a constexpr constructor,
this constructor shall be a constexpr constructor. This constructor shall not
participate in overload resolution unless is_constructible_v<E, const G&>. The
constructor is explicit if and only if is_convertible_v<const G&, E> is false.
template <class G = E> EXPLICIT constexpr expected(unexpected<G>&& e);
Effects: Initializes unexpect as if direct-non-list-initializing
an object of type unexpected<E> with the expression std::move(e).
Postconditions: !bool(*this).
Throws: Any exception thrown by the operations specified in the effect clause.
Remark: If unexpected<E>'s selected constructor is a constexpr constructor,
this constructor shall be a constexpr constructor. The expression inside noexcept is equivalent to: is_nothrow_constructible_v<E, G&&>. This
constructor shall not participate in overload resolution unless is_constructible_v<E, G&&>. The constructor is explicit if and only if is_convertible_v<G&&, E> is false.
template <class... Args> constexpr explicit expected(unexpect_t, Args&&... args);
Effects: Initializes unexpect as if direct-non-list-initializing
an object of type unexpected<E>with the arguments std::forward<Args>(args)....
Postconditions: !bool(*this).
Throws: Any exception thrown by the operations specified in the effect clause.
Remarks: If unexpected<E>'s constructor selected for the initialization is a
constexpr constructor, this constructor shall be a constexpr constructor. This
constructor shall not participate in overload resolution unless is_constructible_v<E, Args&&...>.
template <class U, class... Args> constexpr explicit expected(unexpect_t, initializer_list<U> il, Args&&... args);
Effects: Initializes unexpect as if direct-non-list-initializing
an object of type unexpected<E> with the arguments il, std::forward<Args>(args)....
Postconditions: !bool(*this).
Throws: Any exception thrown by the operations specified in the effect clause.
Remarks: If unexpected<E>'s constructor selected for the initialization is a
constexpr constructor, this constructor shall be a constexpr constructor. This
constructor shall not participate in overload resolution unless is_constructible_v<E, initializer_list<U>&, Args&&...>.
1.12. �.�.4.2 Destructor [expected.object.dtor]
~expected();
Effects: If T is not void and is_trivially_destructible_v<T> != true and bool(*this), calls val.~T(). If is_trivially_destructible_v<E> != true and !bool(*this), calls unexpect.~unexpected<E>().
Remarks: If T is void or is_trivially_destructible_v<T> is true and is_trivially_destructible_v<E> is true then this destructor shall be a
trivial destructor.
1.13. �.�.4.3 Assignment [expected.object.assign]
expected& operator=(const expected& rhs) noexcept(see below);
Effects:
If bool(*this) and bool(rhs),
- 
     assigns *rhstovalifTis notvoid;
otherwise if !bool(*this) and !bool(rhs),
- 
     assigns unexpected(rhs.error())tounexpect;
otherwise if bool(*this) and !bool(rhs),
- 
     if Tisvoid- 
       initializes unexpectas if direct-non-list-initializing an object of typeunexpected<E>withunexpected(rhs.error()). Either
- 
       The didn’t throw, set has_valtofalse, or
- 
       the constructor did throw, and nothing was changed. 
 
- 
       
- 
     otherwise if is_nothrow_copy_constructible_v<E>- 
       destroys valby callingval.~T(),
- 
       initializes unexpectas if direct-non-list-initializing an object of typeunexpected<E>withunexpected(rhs.error()).
 
- 
       
- 
     otherwise if is_nothrow_move_constructible_v<E>- 
       constructs a unexpected<E> tmpfrom*rhs(this can throw),
- 
       destroys valby callingval.~T(),
- 
       initializes unexpectas if direct-non-list-initializing an object of typeunexpected<E>withunexpected(rhs.error()).
 
- 
       
otherwise
- 
     constructs a T tmpfrom*this(this can throw),
- 
     destroys valby callingval.~T(),
- 
     initializes unexpectas if direct-non-list-initializing an object of typeunexpected<E>withunexpected(rhs.error()). Either,- 
       the last constructor didn’t throw, set has_valtofalse, or
- 
       the last constructor did throw, so move-construct the Tfromtmpback into the expected storage (which can’t throw asis_nothrow_move_constructible_v<T>istrue), and rethrow the exception.
 
- 
       
otherwise
- 
     if Tisvoiddestroysunexpectby callingunexpect.~unexpected<E>()
- 
     otherwise if is_nothrow_copy_constructible_v<T>- 
       destroys unexpectby callingunexpect.~unexpected<E>()
- 
       initializes valas if direct-non-list-initializing an object of typeTwith*rhs;
 
- 
       
- 
     otherwise if is_nothrow_move_constructible_v<T>- 
       constructs a T tmpfrom*rhs(this can throw),
- 
       destroys unexpectby callingunexpect.~unexpected<E>()
- 
       initializes valas if direct-non-list-initializing an object of typeTwithmove(tmp);
 
- 
       
- 
     otherwise - 
       constructs a unexpected<E> tmpfromunexpected(this->error())(which can throw),
- 
       destroys unexpectby callingunexpect.~unexpected<E>(),
- 
       initializes valas if direct-non-list-initializing an object of typeTwith*rhs. Either,
- 
       the constructor didn’t throw, set has_valtotrue, or
- 
       the constructor did throw, so move-construct the unexpected<E>fromtmpback into the expected storage (which can’t throw asis_nothrow_move_constructible_v<E>istrue), and rethrow the exception.
 
- 
       
Returns: *this.
Postconditions: bool(rhs) == bool(*this).
Throws: Any exception thrown by the operations specified in the effect clause.
Remarks: If any exception is thrown, bool(*this) and bool(rhs) remain unchanged.
If an exception is thrown during the call to T's or unexpected<E>'s copy
constructor, no effect. If an exception is thrown during the call to T's or unexpected<E>'s copy assignment, the state of its contained value is as defined
by the exception safety guarantee of T's or unexpected<E>'s copy assignment.
This operator shall be defined as deleted unless
- 
     Tisvoidandis_copy_assignable_v<E>andis_copy_constructible_v<E>or
- 
     Tis notvoidandis_copy_assignable_v<T>andis_copy_constructible_v<T>andis_copy_assignable_v<E>andis_copy_constructible_v<E>and (is_nothrow_move_constructible_v<E>oris_nothrow_move_constructible_v<T>).expected& operator=(expected&& rhs) noexcept(see below); 
Effects:
If bool(*this) and bool(rhs),
- 
     move assign *rhstovalifTis notvoid;
otherwise if !bool(*this) and !bool(rhs),
- 
     move assign unexpected(rhs.error())tounexpect;
otherwise if bool(*this) and !bool(rhs),
- 
     if Tisvoid- 
       initializes unexpectas if direct-non-list-initializing an object of typeunexpected<E>withunexpected(move(rhs).error()). Either
- 
       the constructor didn’t throw, set has_valtofalse, or
- 
       the constructor did throw, and nothing was changed. 
 
- 
       
- 
     otherwise if is_nothrow_move_constructible_v<E>- 
       destroys valby callingval.~T(),
- 
       initializes unexpectas if direct-non-list-initializing an object of typeunexpected<E>withunexpected(std::move(rhs.error()));
 
- 
       
- 
     otherwise - 
       move constructs a T tmpfrom*this(which can’t throw asTis nothrow-move-constructible),
- 
       destroys valby callingval.~T(),
- 
       initializes unexpectas if direct-non-list-initializing an object of typeunexpected_type<E>withunexpected(std::move(rhs.error())). Either,
- 
       The constructor didn’t throw, so mark the expected as holding a unexpected_type<E>, or
- 
       The constructor did throw, so move-construct the Tfromtmpback into the expected storage (which can’t throw asTis nothrow-move-constructible), and rethrow the exception.
 
- 
       
otherwise !bool(*this) and bool(rhs),
- 
     if Tisvoiddestroysunexpectby callingunexpect.~unexpected<E>()
- 
     otherwise if is_nothrow_move_constructible_v<T>- 
       destroys unexpectby callingunexpect.~unexpected<E>(),
- 
       initializes valas if direct-non-list-initializing an object of typeTwith*std::move(rhs);
 
- 
       
- 
     otherwise - 
       move constructs a unpepected_type<E> tmpfromunexpected(this->error())(which can’t throw asEis nothrow-move-constructible),
- 
       destroys unexpectby callingunexpect.~unexpected<E>(),
- 
       initializes valas if direct-non-list-initializing an object of typeTwith*std::move(rhs). Either,
- 
       The constructor didn’t throw, set has_valtotrue, or
- 
       The constructor did throw, so move-construct the unexpected<E>fromtmpback into the expected storage (which can’t throw asEis nothrow-move-constructible), and rethrow the exception.
 
- 
       
Returns: *this.
Postconditions: bool(rhs) == bool(*this).
Remarks: The expression inside noexcept is equivalent to: is_nothrow_move_assignable_v<T> && is_nothrow_move_constructible_v<T>.
If any exception is thrown, bool(*this) and bool(rhs) remain
unchanged. If an exception is thrown during the call to T's copy constructor,
no effect. If an exception is thrown during the call to T's copy assignment,
the state of its contained value is as defined by the exception safety guarantee
of T's copy assignment. If an exception is thrown during the call to E's
copy assignment, the state of its contained unexpect is as defined by
the exception safety guarantee of E's copy assignment.
This operator shall be defined as deleted unless
- 
     Tisvoidandis_nothrow_move_constructible_v<E>andis_nothrow_move_assignable_v<E>.
or
- 
     Tis notvoidandis_move_constructible_v<T>andis_move_assignable_v<T>andis_nothrow_move_constructible_v<E>andis_nothrow_move_assignable_v<E>.template <class U = T> expected<T, E>& operator=(U&& v); 
Effects:
If bool(*this), assigns std::forward<U>(v) to val;
otherwise if is_nothrow_constructible_v<T, U&&>
- 
     destroys unexpectby callingunexpect.~unexpected<E>(),
- 
     initializes valas if direct-non-list-initializing an object of typeTwithstd::forward<U>(v)and
- 
     set has_valtotrue;
otherwise
- 
     move constructs a unexpected<E> tmpfromunexpected(this->error())(which can’t throw asEis nothrow-move-constructible),
- 
     destroys unexpectby callingunexpect.~unexpected<E>(),
- 
     initializes valas if direct-non-list-initializing an object of typeTwithstd::forward<U>(v). Either,- 
       the constructor didn’t throw, set has_valtotrue, that is sethas_valtotrue, or
- 
       the constructor did throw, so move construct the unexpected<E>fromtmpback into the expected storage (which can’t throw asEis nothrow-move-constructible), and re-throw the exception.
 
- 
       
Returns: *this.
Postconditions: bool(*this) .
Remarks: If any exception is thrown, bool(*this) remains
 unchanged. If an exception is thrown during the call to T's constructor, no
 effect. If an exception is thrown during the call to T's copy assignment, the
 state of its contained value is as defined by the exception safety guarantee of T's copy assignment.
This function shall not participate in overload resolution unless:
- 
     is_void_v<T>isfalseand
- 
     is_same_v<expected<T,E>, remove_cvref_t<U>>isfalseand
- 
     conjunction_v<is_scalar<T>, is_same<T, decay_t<U>>>isfalse,
- 
     is_constructible_v<T, U>istrue,
- 
     is_assignable_v<T&, U>istrueand
- 
     is_nothrow_move_constructible_v<E>istrue.template <class G = E> expected<T, E>& operator=(const unexpected<G>& e); 
Effects:
If !bool(*this), assigns unexpected(e.error()) to unexpect;
otherwise
- 
     destroys valby callingval.~T()ifTis notvoid,
- 
     initializes unexpectas if direct-non-list-initializing an object of typeunexpected<E>withunexpected(e.error())and sethas_valtofalse.
Returns: *this.
Postconditions: !bool(*this).
Remarks: If any exception is thrown, bool(*this) remains unchanged.
This signature shall not participate in overload resolution unless is_nothrow_copy_constructible_v<E> and is_move_assignable_v<E>.
expected<T, E>& operator=(unexpected<G> && e);
Effects:
If !bool(*this), move assign unexpected(e.error()) to unexpect;
otherwise
- 
     destroys valby callingval.~T()ifTis notvoid,
- 
     initializes unexpectas if direct-non-list-initializing an object of typeunexpected<E>withunexpected(std::move(e.error()))and sethas_valtofalse.
Returns: *this.
Postconditions: !bool(*this).
Remarks: If any exception is thrown, bool(*this) remains unchanged.
This signature shall not participate in overload resolution unless is_nothrow_move_constructible_v<E> and is_move_assignable_v<E>.
void expected<void,E>::emplace();
Effects:
If !bool(*this)
- 
     destroys unexpectby callingunexpect.~unexpected<E>(),
- 
     set has_valtotrue
Postconditions: bool(*this) .
Throws: Nothing
template <class... Args> void emplace(Args&&... args);
Effects:
If bool(*this), assigns val as if
constructing an object of type T with the arguments std::forward<Args>(args)...
otherwise if is_nothrow_constructible_v<T, Args&&...>
- 
     destroys unexpectby callingunexpect.~unexpected<E>(),
- 
     initializes valas if direct-non-list-initializing an object of typeTwithstd::forward<Args>(args)...and
- 
     set has_valtotrue;
otherwise if is_nothrow_move_constructible_v<T>
- 
     constructs a T tmpfromstd::forward<Args>(args)...(which can throw),
- 
     destroys unexpectby callingunexpect.~unexpected<E>(),
- 
     initializes valas if direct-non-list-initializing an object of typeTwithstd::move(tmp)(which can not throw) and
- 
     set has_valtotrue;
otherwise
- 
     move constructs a unexpected<E> tmpfromunexpected(this->error()),
- 
     destroys unexpectby callingunexpect.~unexpected<E>(),
- 
     initializes valas if direct-non-list-initializing an object of typeTwithstd::forward<Args>(args).... Either,- 
       the constructor didn’t throw, set has_valtotrue, that is sethas_valtotrue, or
- 
       the constructor did throw, so move-construct the unexpected<E>fromtmpback into the expected storage (which can’t throw asEis nothrow-move-constructible), and re-throw the exception.
 
- 
       
Postconditions: bool(*this) .
Throws: Any exception thrown by the operations specified in the effect clause.
Remarks: If an exception is thrown during the call to T's assignment, nothing
changes.
This signature shall not participate in overload resolution unless is_nothrow_constructible_v<T, Args&&...>.
template <class U, class... Args> void emplace(initializer_list<U> il, Args&&... args);
Effects: if bool(*this), assigns val as if
constructing an object of type T with the arguments il, std::forward<Args>(args)..., otherwise destroys unexpect by calling unexpect.~unexpected<E>() and initializes val as if
constructing an object of type T with the arguments il, std::forward<Args>(args)....
Postconditions: bool(*this) .
Throws: Any exception thrown by the operations specified in the effect clause.
Remarks: If an exception is thrown during the call to T's assignment nothing
changes.
The function shall not participate in overload resolution unless: T is not void and is_nothrow_constructible_v<T, initializer_list<U>&, Args&&...>.
1.14. �.�.4.4 Swap [expected.object.swap]
void swap(expected<T, E>& rhs) noexcept(see below);
Effects: if bool(*this) and bool(rhs),
- 
     calls using std::swap; swap(val, rhs.val),
otherwise if !bool(*this) and !bool(rhs),
- 
     calls using std::swap; swap(unexpect, rhs.unexpect),
otherwise if !bool(*this) and bool(rhs),
- 
     calls rhs.swap(*this),
otherwise
- 
     if Tisvoid- 
       initializes unexpectas if direct-non-list-initializing an object of typeunexpected<E>withunexpected(std::move(rhs)). Either
- 
       the constructor didn’t throw, set has_valtofalse, destroysunexpectby callingrhs.unexpect.~unexpected<E>()setrhs.has_valtotrue.
- 
       the constructor did throw, rethrow the exception. 
 
- 
       
- 
     otherwise if is_nothrow_move_constructible_v<E>,- 
       the unexpectofrhsis moved to a temporary variabletmpof typeunexpected_type,
- 
       followed by destruction of unexpectas if byrhs.unexpect.unexpected<E>::~unexpected<E>(),
- 
       rhs.valis direct-initialized fromstd::move(*other),
- 
       followed by destruction of rhs.valas if byrhs.val->~T(),
- 
       the unexpectofthisis direct-initialized fromstd::move(tmp), after this,thisdoes not contain a value; andbool(rhs).
 
- 
       
- 
     otherwise if is_nothrow_move_constructible_v<T>,- 
       rhs.valis moved to a temporary variabletmpof typeT,
- 
       followed by destruction of rhs.valas if byrhs.val.~T(),
- 
       the unexpectofrhsis direct-initialized fromunexpected(std::move(other.error())),
- 
       followed by destruction of unexpectas if byrhs.unexpect->unexpected<E>::~unexpected<E>(),
- 
       valis direct-initialized fromstd::move(tmp), after this,thisdoes not contain a value; andbool(rhs).
 
- 
       
Throws: Any exceptions that the expressions in the Effects clause throw.
 Adapt swap Remarks once Effects are good.
Remarks: The expression inside noexcept is equivalent to: is_nothrow_move_constructible_v<T> && noexcept(swap(declval<T&>(), declval<T&>())) && is_nothrow_move_constructible_v<E> && noexcept(swap(declval<E&>(), declval<E&>())). The function shall not
participate in overload resolution unless: Lvalues of type T shall be Swappable, Lvalues of type E shall be Swappable and is_move_constructible_v<E> is_move_constructible_v<E> is_move_constructible_v<E> or is_move_constructible_v<T>.
1.15. �.�.4.5 Observers [expected.object.observe]
constexpr const T* operator->() const; T* operator->();
Requires: bool(*this) .
Returns: addressof(val).
Remarks: Unless T is a user-defined type with overloaded unary operator&,
the first operator shall be a constexpr function. 
The operator shall not participate in overload resolution unless: T is not void.
constexpr const T& operator *() const&; T& operator *() &;
Requires: bool(*this) .
Returns: val.
Remarks: The first operator shall be a constexpr function.
The operator shall not participate in overload resolution unless: T is not void.
constexpr T&& operator *() &&; constexpr const T&& operator *() const&&;
Requires: bool(*this) .
Returns: std::move(val).
Remarks: This operator shall be a constexpr function.
The operator shall not participate in overload resolution unless: T is not void.
constexpr explicit operator bool() noexcept;
Returns: has_val.
Remarks: This operator shall be a constexpr function.
constexpr bool has_value() const noexcept;
Returns: has_val.
Remarks: This function shall be a constexpr function.
constexpr void expected<void, E>::value() const;
Throws: bad_expected_access(error()) if !bool(*this).
constexpr const T& expected::value() const&; constexpr T& expected::value() &;
Returns: val, if bool(*this) .
Throws: bad_expected_access(error()) if !bool(*this).
Remarks: These functions shall be constexpr functions.
The operator shall not participate in overload resolution unless: T is not void.
constexpr T&& expected::value() &&; constexpr const T&& expected::value() const&&;
Returns: std::move(val), if bool(*this) .
Throws: bad_expected_access(error()) if !bool(*this).
Remarks: These functions shall be constexpr functions.
The operator shall not participate in overload resolution unless: T is not void.
constexpr const E& error() const&; constexpr E& error() &;
Requires: !bool(*this).
Returns: unexpect.value().
Remarks: The first function shall be a constexpr function.
constexpr E&& error() &&; constexpr const E&& error() const &&;
Requires: !bool(*this).
Returns: std::move(unexpect.value()).
Remarks: The first function shall be a constexpr function.
template <class U> constexpr T value_or(U&& v) const&;
Effects: Equivalent to return bool(*this) ? **this : static_cast<T>(std::forward<U>(v));.
Remarks: If is_copy_constructible_v<T> && is_convertible_v<U&&, T> is false the program is ill-formed.
template <class U> constexpr T value_or(U&& v) &&;
Effects: Equivalent to return bool(*this) ? std::move(**this) : static_cast<T>(std::forward<U>(v));.
Remarks: If is_move_constructible_v<T> and is_convertible_v<U&&, T> is false the program is ill-formed.
1.16. �.�.5 unexpect tag [expected.unexpect]
struct unexpect_t { explicit unexpect_t() = default; }; inline constexpr unexpect_t unexpect{};
1.17. �.�.6 Template Class bad_expected_access [expected.bad_expected_access]
template <class E> class bad_expected_access : public bad_expected_access<void> { public: explicit bad_expected_access(E); virtual const char* what() const noexcept override; E& error() &; const E& error() const&; E&& error() &&; const E&& error() const&&; private: E val; // exposition only };
 Wondering if we just need an const & overload as we do for system_error.
The template class 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 expected object that contains an unexpected<E>.
bad_expected_access::bad_expected_access(E e);
Effects: Initialize val with e.
Postconditions: what() returns an implementation-defined NTBS.
const E& error() const&; E& error() &;
Effects: Equivalent to: return val;
E&& error() &&; const E&& error() const &&;
Effects: Equivalent to: return std::move(val);
virtual const char* what() const noexcept override;
Returns: An implementation-defined NTBS.
1.18. �.�.7 Class bad_expected_access<void> [expected.bad_expected_access_base]
template <> class bad_expected_access<void> : public exception { public: explicit bad_expected_access(); };
1.19. �.�.8 Expected Equality operators [expected.relational_op]
template <class T1, class E1, class T2, class E2> constexpr bool operator==(const expected<T1, E1>& x, const expected<T2, E2>& y);
Requires: The expressions *x == *y and unexpected(x.error()) == unexpected(y.error()) shall be well-formed and its result
shall be convertible to bool.
Returns: If bool(x) != bool(y), false; otherwise if bool(x) == false, x.error() == y.error(); otherwise true if T is void or *x == *y otherwise.
Remarks: Specializations of this function template, for which T is void or *x == *y and x.error() == y.error() are core constant expression, shall be constexpr functions.
template <class T1, class E1, class T2, class E2> constexpr bool operator!=(const expected<T1, E1>& x, const expected<T2, E2>& y);
Requires: The expressions *x != *y and x.error() != y.error() shall be
well-formed and its result shall be convertible to bool.
Returns: If bool(x) != bool(y), true; otherwise if bool(x) == false, x.error() != y.error(); otherwise true if T is void or *x != *y.
Remarks: Specializations of this function template, for which T is void or *x != *y and x.error() != y.error() are core
constant expression, shall be constexpr functions.
1.20. �.�.9 Comparison with T [expected.comparison_T]
template <class T, class E, class U> constexpr bool operator==(const expected<T, E>& x, const U& v); template <class U, class T, class E> constexpr bool operator==(const U& v, const expected<T, E>& x);
Requires: T is not void and the expression *x == v shall be well-formed
and its result shall be convertible to bool. [ Note: T need not be EqualityComparable. - end note]
Effects: Equivalent to: return bool(x) ? *x == v : false;.
template <class T, class E, class U> constexpr bool operator!=(const expected<T, E>& x, const U& v); template <class U, class T, class E> constexpr bool operator!=(const U& v, const expected<T, E>& x);
Requires: T is not void and the expression *x == v shall be well-formed
and its result shall be convertible to bool. [ Note: T need not be EqualityComparable. - end note]
Effects: Equivalent to: return bool(x) ? *x != v : false;.
1.21. �.�.10 Comparison with unexpected<E> [expected.comparison_unexpected_E]
template <class T, class E, class G> constexpr bool operator==(const expected<T, E>& x, const unexpected<G>& e); template <class G, class T, class E> constexpr bool operator==(const unexpected<G>& e, const expected<T, E>& x);
Requires: The expression unexpected(x.error()) == e shall be well-formed and
its result shall be convertible to bool.
Effects: Equivalent to: return bool(x) ? false : unexpected(x.error()) == e;.
template <class T, class E, class G> constexpr bool operator!=(const expected<T, E>& x, const unexpected<G>& e); template <class G, class T, class E> constexpr bool operator!=(const unexpected<G>& e, const expected<T, E>& x);
Requires: The expression unexpected(x.error()) != e shall be well-formed and
its result shall be convertible to bool. Effects: Equivalent to: return bool(x) ? true : unexpected(x.error()) != e;.
1.22. �.�.11 Specialized algorithms [expected.specalg]
template <class T, class E> void swap(expected<T, E>& x, expected<T, E>& y) noexcept(noexcept(x.swap(y)));
Effects: Calls x.swap(y).
Remarks: This function shall not participate in overload resolution unless T is void or is_move_constructible_v<T> is true, is_swappable_v<T> is true and is_move_constructible_v<E> is true and is_swappable_v<E> is true.
2. Open Questions
std::expected is a vocabulary type with an opinionated design and a proven
record under varied forms in a multitude of codebases. Its current form has
undergone multiple revisions and received substantial feedback, falling roughly
in the following categories:
- 
     Ergonomics: is this the right way to expose such functionality? 
- 
     Disappointment: should we expose this in the Standard, given C++'s existing error handling mechanisms? 
- 
     STL usage: should the Standard Template Library adopt this class, at which pace, and where? 
LEWG and EWG have nonetheless reached consensus that a class of this general approach is probably desirable, and the only way to truly answer these questions is to try it out in a TS and ask for explicit feedback from developers. The authors hope that developers will provide new information which they’ll be able to communicate to the Committee.
Here are open questions, and questions which the Committee thinks are settled and which new information can justify revisiting.
2.1. Ergonomics
- 
     Name: - 
       Is expectedthe right name?
- 
       Does it express intent both as a consumer and a producer? 
 
- 
       
- 
     Is Ea salient property ofexpected?
- 
     Is expected<void, E>clear on what it expresses as a return type?
- 
     Would it make sense for expectedto support containing bothTandE(in some designs, either one of them being optional), or is this use case better handled by a separate proposal?
- 
     Is the order of parameters <T, E>appropriate?
- 
     Is usage of expected"viral" in a codebase, or can it be adopted incrementally?
- 
     Comparisons: - 
       Are ==and!=useful?
- 
       Should other comparisons be provided? 
- 
       What usages of expectedmandate putting instances in amap, or other such container?
- 
       Should hashbe provided?
- 
       What usages of expectedmandate putting instances in anunordered_map, or other such container?
- 
       Should expected<T, E>always be comparable ifTis comparable, even ifEis not comparable?
 
- 
       
- 
     Error type E:- 
       Ehas no default. Should it?
- 
       Should expectedbe specialized for particularEtypes such asexception_ptrand how?
- 
       Should expectedhandleEtypes with a built-in "success" value any differently and how?
- 
       expectedis not implicitly constructible from anE, even when unambiguous fromT, because as a vocabulary type it wants unexpected error construction to be verbose, and require hopping through anunexpected. Is the verbosity extraneous?
 
- 
       
- 
     Does usage of this class cause a meaningful performance impact compared to using error codes? 
- 
     The accessor design offers a terse unchecked dereference operator (expected to be used alongside the implicit boolconversion), as well asvalue()anderror()accessors which are checked. Is that a gotcha, or is it similar enough to classes such asoptionalto be unsurprising?
- 
     Is bad_expected_accessthe right thing to throw?
- 
     Should some members be nodiscard?
2.2. Disappointment
C++ already supports exceptions and error codes, expected would be a third
kind of error handling.
- 
     where does expectedwork better than either exceptions or error handling?
- 
     expectedwas designed to be particularly well suited to APIs which require their immediate caller to consider an error scenario. Do it succeed in that purpose?
- 
     Do codebases successfully compose these three types of error handling? 
- 
     Is debuggability any harder? 
- 
     Is it easy to teach C++ as a whole with a third type of error handling? 
2.3. STL Usage
- 
     Should expectedbe used in the STL at the same time as it gets standardized?
- 
     Where, considering std2may be a good place to change APIs?