22 General utilities library [utilities]

22.5 Optional objects [optional]

22.5.1 In general [optional.general]

Subclause [optional] describes class template optional that represents optional objects.
An optional object is an object that contains the storage for another object and manages the lifetime of this contained object, if any.
The contained object may be initialized after the optional object has been initialized, and may be destroyed before the optional object has been destroyed.
The initialization state of the contained object is tracked by the optional object.

22.5.2 Header <optional> synopsis [optional.syn]

#include <compare> // see [compare.syn] namespace std { // [optional.optional], class template optional template<class T> class optional; template<class T> concept is-derived-from-optional = requires(const T& t) { // exposition only []<class U>(const optional<U>&){ }(t); }; // [optional.nullopt], no-value state indicator struct nullopt_t{see below}; inline constexpr nullopt_t nullopt(unspecified); // [optional.bad.access], class bad_optional_access class bad_optional_access; // [optional.relops], relational operators template<class T, class U> constexpr bool operator==(const optional<T>&, const optional<U>&); template<class T, class U> constexpr bool operator!=(const optional<T>&, const optional<U>&); template<class T, class U> constexpr bool operator<(const optional<T>&, const optional<U>&); template<class T, class U> constexpr bool operator>(const optional<T>&, const optional<U>&); template<class T, class U> constexpr bool operator<=(const optional<T>&, const optional<U>&); template<class T, class U> constexpr bool operator>=(const optional<T>&, const optional<U>&); template<class T, three_way_comparable_with<T> U> constexpr compare_three_way_result_t<T, U> operator<=>(const optional<T>&, const optional<U>&); // [optional.nullops], comparison with nullopt template<class T> constexpr bool operator==(const optional<T>&, nullopt_t) noexcept; template<class T> constexpr strong_ordering operator<=>(const optional<T>&, nullopt_t) noexcept; // [optional.comp.with.t], comparison with T template<class T, class U> constexpr bool operator==(const optional<T>&, const U&); template<class T, class U> constexpr bool operator==(const T&, const optional<U>&); template<class T, class U> constexpr bool operator!=(const optional<T>&, const U&); template<class T, class U> constexpr bool operator!=(const T&, const optional<U>&); template<class T, class U> constexpr bool operator<(const optional<T>&, const U&); template<class T, class U> constexpr bool operator<(const T&, const optional<U>&); template<class T, class U> constexpr bool operator>(const optional<T>&, const U&); template<class T, class U> constexpr bool operator>(const T&, const optional<U>&); template<class T, class U> constexpr bool operator<=(const optional<T>&, const U&); template<class T, class U> constexpr bool operator<=(const T&, const optional<U>&); template<class T, class U> constexpr bool operator>=(const optional<T>&, const U&); template<class T, class U> constexpr bool operator>=(const T&, const optional<U>&); template<class T, class U> requires (!is-derived-from-optional<U>) && three_way_comparable_with<T, U> constexpr compare_three_way_result_t<T, U> operator<=>(const optional<T>&, const U&); // [optional.specalg], specialized algorithms template<class T> constexpr void swap(optional<T>&, optional<T>&) noexcept(see below); template<class T> constexpr optional<see below> make_optional(T&&); template<class T, class... Args> constexpr optional<T> make_optional(Args&&... args); template<class T, class U, class... Args> constexpr optional<T> make_optional(initializer_list<U> il, Args&&... args); // [optional.hash], hash support template<class T> struct hash; template<class T> struct hash<optional<T>>; }

22.5.3 Class template optional [optional.optional]

22.5.3.1 General [optional.optional.general]

namespace std { template<class T> class optional { public: using value_type = T; // [optional.ctor], constructors constexpr optional() noexcept; constexpr optional(nullopt_t) noexcept; constexpr optional(const optional&); constexpr optional(optional&&) noexcept(see below); template<class... Args> constexpr explicit optional(in_place_t, Args&&...); template<class U, class... Args> constexpr explicit optional(in_place_t, initializer_list<U>, Args&&...); template<class U = T> constexpr explicit(see below) optional(U&&); template<class U> constexpr explicit(see below) optional(const optional<U>&); template<class U> constexpr explicit(see below) optional(optional<U>&&); // [optional.dtor], destructor constexpr ~optional(); // [optional.assign], assignment constexpr optional& operator=(nullopt_t) noexcept; constexpr optional& operator=(const optional&); constexpr optional& operator=(optional&&) noexcept(see below); template<class U = T> constexpr optional& operator=(U&&); template<class U> constexpr optional& operator=(const optional<U>&); template<class U> constexpr optional& operator=(optional<U>&&); template<class... Args> constexpr T& emplace(Args&&...); template<class U, class... Args> constexpr T& emplace(initializer_list<U>, Args&&...); // [optional.swap], swap constexpr void swap(optional&) noexcept(see below); // [optional.observe], observers constexpr const T* operator->() const noexcept; constexpr T* operator->() noexcept; constexpr const T& operator*() const & noexcept; constexpr T& operator*() & noexcept; constexpr T&& operator*() && noexcept; constexpr const T&& operator*() const && noexcept; constexpr explicit operator bool() const noexcept; constexpr bool has_value() const noexcept; constexpr const T& value() const &; constexpr T& value() &; constexpr T&& value() &&; constexpr const T&& value() const &&; template<class U> constexpr T value_or(U&&) const &; template<class U> constexpr T value_or(U&&) &&; // [optional.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 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 optional or_else(F&& f) &&; template<class F> constexpr optional or_else(F&& f) const &; // [optional.mod], modifiers constexpr void reset() noexcept; private: T *val; // exposition only }; template<class T> optional(T) -> optional<T>; }
Any instance of optional<T> at any given time either contains a value or does not contain a value.
When an instance of optional<T> contains a value, it means that an object of type T, referred to as the optional object's contained value, is allocated within the storage of the optional object.
Implementations are not permitted to use additional storage, such as dynamic memory, to allocate its contained value.
When an object of type optional<T> is contextually converted to bool, the conversion returns true if the object contains a value; otherwise the conversion returns false.
When an optional<T> object contains a value, member val points to the contained value.
T shall be a type other than cv in_place_t or cv nullopt_t that meets the Cpp17Destructible requirements (Table 35).

22.5.3.2 Constructors [optional.ctor]

The exposition-only variable template converts-from-any-cvref is used by some constructors for optional.
template<class T, class W> constexpr bool converts-from-any-cvref = // exposition only disjunction_v<is_constructible<T, W&>, is_convertible<W&, T>, is_constructible<T, W>, is_convertible<W, T>, is_constructible<T, const W&>, is_convertible<const W&, T>, is_constructible<T, const W>, is_convertible<const W, T>>;
constexpr optional() noexcept; constexpr optional(nullopt_t) noexcept;
Postconditions: *this does not contain a value.
Remarks: No contained value is initialized.
For every object type T these constructors are constexpr constructors ([dcl.constexpr]).
constexpr optional(const optional& rhs);
Effects: If rhs contains a value, direct-non-list-initializes the contained value with *rhs.
Postconditions: rhs.has_value() == this->has_value().
Throws: Any exception thrown by the selected constructor of T.
Remarks: This constructor is defined as deleted unless is_copy_constructible_v<T> is true.
If is_trivially_copy_constructible_v<T> is true, this constructor is trivial.
constexpr optional(optional&& rhs) noexcept(see below);
Constraints: is_move_constructible_v<T> is true.
Effects: If rhs contains a value, direct-non-list-initializes the contained value with std​::​move(*rhs).
rhs.has_value() is unchanged.
Postconditions: rhs.has_value() == this->has_value().
Throws: Any exception thrown by the selected constructor of T.
Remarks: The exception specification is equivalent to is_nothrow_move_constructible_v<T>.
If is_trivially_move_constructible_v<T> is true, this constructor is trivial.
template<class... Args> constexpr explicit optional(in_place_t, Args&&... args);
Constraints: is_constructible_v<T, Args...> is true.
Effects: Direct-non-list-initializes the contained value with std​::​forward<Args>(args)....
Postconditions: *this contains a value.
Throws: Any exception thrown by the selected constructor of T.
Remarks: If T's constructor selected for the initialization is a constexpr constructor, this constructor is a constexpr constructor.
template<class U, class... Args> constexpr explicit optional(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 the contained value with il, std​::​forward<Args>(args)....
Postconditions: *this contains a value.
Throws: Any exception thrown by the selected constructor of T.
Remarks: If T's constructor selected for the initialization is a constexpr constructor, this constructor is a constexpr constructor.
template<class U = T> constexpr explicit(see below) optional(U&& v);
Constraints:
  • is_constructible_v<T, U> is true,
  • is_same_v<remove_cvref_t<U>, in_place_t> is false,
  • is_same_v<remove_cvref_t<U>, optional> is false, and
  • if T is cv bool, remove_cvref_t<U> is not a specialization of optional.
Effects: Direct-non-list-initializes the contained value with std​::​forward<U>(v).
Postconditions: *this contains a value.
Throws: Any exception thrown by the selected constructor of T.
Remarks: If T's selected constructor is a constexpr constructor, this constructor is a constexpr constructor.
The expression inside explicit is equivalent to: !is_convertible_v<U, T>
template<class U> constexpr explicit(see below) optional(const optional<U>& rhs);
Constraints:
  • is_constructible_v<T, const U&> is true, and
  • if T is not cv bool, converts-from-any-cvref<T, optional<U>> is false.
Effects: If rhs contains a value, direct-non-list-initializes the contained value with *rhs.
Postconditions: rhs.has_value() == this->has_value().
Throws: Any exception thrown by the selected constructor of T.
Remarks: The expression inside explicit is equivalent to: !is_convertible_v<const U&, T>
template<class U> constexpr explicit(see below) optional(optional<U>&& rhs);
Constraints:
  • is_constructible_v<T, U> is true, and
  • if T is not cv bool, converts-from-any-cvref<T, optional<U>> is false.
Effects: If rhs contains a value, direct-non-list-initializes the contained value with std​::​move(*rhs).
rhs.has_value() is unchanged.
Postconditions: rhs.has_value() == this->has_value().
Throws: Any exception thrown by the selected constructor of T.
Remarks: The expression inside explicit is equivalent to: !is_convertible_v<U, T>

22.5.3.3 Destructor [optional.dtor]

constexpr ~optional();
Effects: If is_trivially_destructible_v<T> != true and *this contains a value, calls val->T::~T()
Remarks: If is_trivially_destructible_v<T> is true, then this destructor is trivial.

22.5.3.4 Assignment [optional.assign]

constexpr optional<T>& operator=(nullopt_t) noexcept;
Effects: If *this contains a value, calls val->T​::​~T() to destroy the contained value; otherwise no effect.
Postconditions: *this does not contain a value.
Returns: *this.
constexpr optional<T>& operator=(const optional& rhs);
Effects: See Table 58.
Table 58: optional​::​operator=(const optional&) effects [tab:optional.assign.copy]
*this contains a value
*this does not contain a value
rhs contains a value
assigns *rhs to the contained value
direct-non-list-initializes the contained value with *rhs
rhs does not contain a value
destroys the contained value by calling val->T​::​~T()
no effect
Postconditions: rhs.has_value() == this->has_value().
Returns: *this.
Remarks: If any exception is thrown, the result of the expression this->has_value() remains 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.
This operator is defined as deleted unless is_copy_constructible_v<T> is true and is_copy_assignable_v<T> is true.
If is_trivially_copy_constructible_v<T> && is_trivially_copy_assignable_v<T> && is_trivially_destructible_v<T> is true, this assignment operator is trivial.
constexpr optional& operator=(optional&& rhs) noexcept(see below);
Constraints: is_move_constructible_v<T> is true and is_move_assignable_v<T> is true.
Effects: See Table 59.
The result of the expression rhs.has_value() remains unchanged.
Table 59: optional​::​operator=(optional&&) effects [tab:optional.assign.move]
*this contains a value
*this does not contain a value
rhs contains a value
assigns std​::​move(*rhs) to the contained value
direct-non-list-initializes the contained value with std​::​move(*rhs)
rhs does not contain a value
destroys the contained value by calling val->T​::​~T()
no effect
Postconditions: rhs.has_value() == this->has_value().
Returns: *this.
Remarks: The exception specification is equivalent to: is_nothrow_move_assignable_v<T> && is_nothrow_move_constructible_v<T>
If any exception is thrown, the result of the expression this->has_value() remains unchanged.
If an exception is thrown during the call to T's move constructor, the state of *rhs.val is determined by the exception safety guarantee of T's move constructor.
If an exception is thrown during the call to T's move assignment, the state of *val and *rhs.val is determined by the exception safety guarantee of T's move assignment.
If is_trivially_move_constructible_v<T> && is_trivially_move_assignable_v<T> && is_trivially_destructible_v<T> is true, this assignment operator is trivial.
template<class U = T> constexpr optional<T>& operator=(U&& v);
Constraints: is_same_v<remove_cvref_t<U>, optional> is false, conjunction_v<is_scalar<T>, is_same<T, decay_t<U>>> is false, is_constructible_v<T, U> is true, and is_assignable_v<T&, U> is true.
Effects: If *this contains a value, assigns std​::​forward<U>(v) to the contained value; otherwise direct-non-list-initializes the contained value with std​::​forward<U>(v).
Postconditions: *this contains a value.
Returns: *this.
Remarks: If any exception is thrown, the result of the expression this->has_value() remains unchanged.
If an exception is thrown during the call to T's constructor, the state of v is determined by the exception safety guarantee of T's constructor.
If an exception is thrown during the call to T's assignment, the state of *val and v is determined by the exception safety guarantee of T's assignment.
template<class U> constexpr optional<T>& operator=(const optional<U>& rhs);
Constraints:
  • is_constructible_v<T, const U&> is true,
  • is_assignable_v<T&, const U&> is true,
  • converts-from-any-cvref<T, optional<U>> is false,
  • is_assignable_v<T&, optional<U>&> is false,
  • is_assignable_v<T&, optional<U>&&> is false,
  • is_assignable_v<T&, const optional<U>&> is false, and
  • is_assignable_v<T&, const optional<U>&&> is false.
Effects: See Table 60.
Table 60: optional​::​operator=(const optional<U>&) effects [tab:optional.assign.copy.templ]
*this contains a value
*this does not contain a value
rhs contains a value
assigns *rhs to the contained value
direct-non-list-initializes the contained value with *rhs
rhs does not contain a value
destroys the contained value by calling val->T​::​~T()
no effect
Postconditions: rhs.has_value() == this->has_value().
Returns: *this.
Remarks: If any exception is thrown, the result of the expression this->has_value() remains unchanged.
If an exception is thrown during the call to T's constructor, the state of *rhs.val is determined by the exception safety guarantee of T's constructor.
If an exception is thrown during the call to T's assignment, the state of *val and *rhs.val is determined by the exception safety guarantee of T's assignment.
template<class U> constexpr optional<T>& operator=(optional<U>&& rhs);
Constraints:
  • is_constructible_v<T, U> is true,
  • is_assignable_v<T&, U> is true,
  • converts-from-any-cvref<T, optional<U>> is false,
  • is_assignable_v<T&, optional<U>&> is false,
  • is_assignable_v<T&, optional<U>&&> is false,
  • is_assignable_v<T&, const optional<U>&> is false, and
  • is_assignable_v<T&, const optional<U>&&> is false.
Effects: See Table 61.
The result of the expression rhs.has_value() remains unchanged.
Table 61: optional​::​operator=(optional<U>&&) effects [tab:optional.assign.move.templ]
*this contains a value
*this does not contain a value
rhs contains a value
assigns std​::​move(*rhs) to the contained value
direct-non-list-initializes the contained value with std​::​move(*rhs)
rhs does not contain a value
destroys the contained value by calling val->T​::​~T()
no effect
Postconditions: rhs.has_value() == this->has_value().
Returns: *this.
Remarks: If any exception is thrown, the result of the expression this->has_value() remains unchanged.
If an exception is thrown during the call to T's constructor, the state of *rhs.val is determined by the exception safety guarantee of T's constructor.
If an exception is thrown during the call to T's assignment, the state of *val and *rhs.val is determined by the exception safety guarantee of T's assignment.
template<class... Args> constexpr T& emplace(Args&&... args);
Mandates: is_constructible_v<T, Args...> is true.
Effects: Calls *this = nullopt.
Then direct-non-list-initializes the contained value with std​::​forward​<Args>(args)....
Postconditions: *this contains a value.
Returns: A reference to the new contained value.
Throws: Any exception thrown by the selected constructor of T.
Remarks: If an exception is thrown during the call to T's constructor, *this does not contain a value, and the previous *val (if any) has been destroyed.
template<class U, class... Args> constexpr T& emplace(initializer_list<U> il, Args&&... args);
Constraints: is_constructible_v<T, initializer_list<U>&, Args...> is true.
Effects: Calls *this = nullopt.
Then direct-non-list-initializes the contained value with il, std​::​​forward<Args>(args)....
Postconditions: *this contains a value.
Returns: A reference to the new contained value.
Throws: Any exception thrown by the selected constructor of T.
Remarks: If an exception is thrown during the call to T's constructor, *this does not contain a value, and the previous *val (if any) has been destroyed.

22.5.3.5 Swap [optional.swap]

constexpr void swap(optional& rhs) noexcept(see below);
Mandates: is_move_constructible_v<T> is true.
Preconditions: T meets the Cpp17Swappable requirements ([swappable.requirements]).
Effects: See Table 62.
Table 62: optional​::​swap(optional&) effects [tab:optional.swap]
*this contains a value
*this does not contain a value
rhs contains a value
calls swap(*(*this), *rhs)
direct-non-list-initializes the contained value of *this with std​::​move(*rhs), followed by rhs.val->T​::​~T(); postcondition is that *this contains a value and rhs does not contain a value
rhs does not contain a value
direct-non-list-initializes the contained value of rhs with std​::​move(*(*this)), followed by val->T​::​~T(); postcondition is that *this does not contain a value and rhs contains a value
no effect
Throws: Any exceptions thrown by the operations in the relevant part of Table 62.
Remarks: The exception specification is equivalent to: is_nothrow_move_constructible_v<T> && is_nothrow_swappable_v<T>
If any exception is thrown, the results of the expressions this->has_value() and rhs.has_value() remain unchanged.
If an exception is thrown during the call to function swap, the state of *val and *rhs.val is determined by the exception safety guarantee of swap for lvalues of T.
If an exception is thrown during the call to T's move constructor, the state of *val and *rhs.val is determined by the exception safety guarantee of T's move constructor.

22.5.3.6 Observers [optional.observe]

constexpr const T* operator->() const noexcept; constexpr T* operator->() noexcept;
Preconditions: *this contains a value.
Returns: val.
Remarks: These functions are constexpr functions.
constexpr const T& operator*() const & noexcept; constexpr T& operator*() & noexcept;
Preconditions: *this contains a value.
Returns: *val.
Remarks: These functions are constexpr functions.
constexpr T&& operator*() && noexcept; constexpr const T&& operator*() const && noexcept;
Preconditions: *this contains a value.
Effects: Equivalent to: return std​::​move(*val);
constexpr explicit operator bool() const noexcept;
Returns: true if and only if *this contains a value.
Remarks: This function is a constexpr function.
constexpr bool has_value() const noexcept;
Returns: true if and only if *this contains a value.
Remarks: This function is a constexpr function.
constexpr const T& value() const &; constexpr T& value() &;
Effects: Equivalent to: return has_value() ? *val : throw bad_optional_access();
constexpr T&& value() &&; constexpr const T&& value() const &&;
Effects: Equivalent to: return has_value() ? std::move(*val) : throw bad_optional_access();
template<class U> constexpr T value_or(U&& v) const &;
Mandates: is_copy_constructible_v<T> && is_convertible_v<U&&, T> is true.
Effects: Equivalent to: return 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_convertible_v<U&&, T> is true.
Effects: Equivalent to: return has_value() ? std::move(**this) : static_cast<T>(std::forward<U>(v));

22.5.3.7 Monadic operations [optional.monadic]

template<class F> constexpr auto and_then(F&& f) &; template<class F> constexpr auto and_then(F&& f) const &;
Let U be invoke_result_t<F, decltype(value())>.
Mandates: remove_cvref_t<U> is a specialization of optional.
Effects: Equivalent to: if (*this) { return invoke(std::forward<F>(f), value()); } else { return remove_cvref_t<U>(); }
template<class F> constexpr auto and_then(F&& f) &&; template<class F> constexpr auto and_then(F&& f) const &&;
Let U be invoke_result_t<F, decltype(std​::​move(value()))>.
Mandates: remove_cvref_t<U> is a specialization of optional.
Effects: Equivalent to: if (*this) { return invoke(std::forward<F>(f), std::move(value())); } else { return remove_cvref_t<U>(); }
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(value())>>.
Mandates: U is a non-array object type other than in_place_t or nullopt_t.
The declaration U u(invoke(std::forward<F>(f), value())); is well-formed for some invented variable u.
[Note 1: 
There is no requirement that U is movable ([dcl.init.general]).
— end note]
Returns: If *this contains a value, an optional<U> object whose contained value is direct-non-list-initialized with invoke(std​::​forward<F>(f), value()); otherwise, optional<U>().
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(value()))>>.
Mandates: U is a non-array object type other than in_place_t or nullopt_t.
The declaration U u(invoke(std::forward<F>(f), std::move(value()))); is well-formed for some invented variable u.
[Note 2: 
There is no requirement that U is movable ([dcl.init.general]).
— end note]
Returns: If *this contains a value, an optional<U> object whose contained value is direct-non-list-initialized with invoke(std​::​forward<F>(f), std​::​move(value())); otherwise, optional<U>().
template<class F> constexpr optional or_else(F&& f) const &;
Constraints: F models invocable<> and T models copy_constructible.
Mandates: is_same_v<remove_cvref_t<invoke_result_t<F>>, optional> is true.
Effects: Equivalent to: if (*this) { return *this; } else { return std::forward<F>(f)(); }
template<class F> constexpr optional or_else(F&& f) &&;
Constraints: F models invocable<> and T models move_constructible.
Mandates: is_same_v<remove_cvref_t<invoke_result_t<F>>, optional> is true.
Effects: Equivalent to: if (*this) { return std::move(*this); } else { return std::forward<F>(f)(); }

22.5.3.8 Modifiers [optional.mod]

constexpr void reset() noexcept;
Effects: If *this contains a value, calls val->T​::​~T() to destroy the contained value; otherwise no effect.
Postconditions: *this does not contain a value.

22.5.4 No-value state indicator [optional.nullopt]

struct nullopt_t{see below}; inline constexpr nullopt_t nullopt(unspecified);
The struct nullopt_t is an empty class type used as a unique type to indicate the state of not containing a value for optional objects.
In particular, optional<T> has a constructor with nullopt_t as a single argument; this indicates that an optional object not containing a value shall be constructed.
Type nullopt_t shall not have a default constructor or an initializer-list constructor, and shall not be an aggregate.

22.5.5 Class bad_optional_access [optional.bad.access]

namespace std { class bad_optional_access : public exception { public: // see [exception] for the specification of the special member functions const char* what() const noexcept override; }; }
The class bad_optional_access defines the type of objects thrown as exceptions to report the situation where an attempt is made to access the value of an optional object that does not contain a value.
const char* what() const noexcept override;
Returns: An implementation-defined ntbs.

22.5.6 Relational operators [optional.relops]

template<class T, class U> constexpr bool operator==(const optional<T>& x, const optional<U>& y);
Mandates: The expression *x == *y is well-formed and its result is convertible to bool.
[Note 1: 
T need not be Cpp17EqualityComparable.
— end note]
Returns: If x.has_value() != y.has_value(), false; otherwise if x.has_value() == false, true; otherwise *x == *y.
Remarks: Specializations of this function template for which *x == *y is a core constant expression are constexpr functions.
template<class T, class U> constexpr bool operator!=(const optional<T>& x, const optional<U>& y);
Mandates: The expression *x != *y is well-formed and its result is convertible to bool.
Returns: If x.has_value() != y.has_value(), true; otherwise, if x.has_value() == false, false; otherwise *x != *y.
Remarks: Specializations of this function template for which *x != *y is a core constant expression are constexpr functions.
template<class T, class U> constexpr bool operator<(const optional<T>& x, const optional<U>& y);
Mandates: *x < *y is well-formed and its result is convertible to bool.
Returns: If !y, false; otherwise, if !x, true; otherwise *x < *y.
Remarks: Specializations of this function template for which *x < *y is a core constant expression are constexpr functions.
template<class T, class U> constexpr bool operator>(const optional<T>& x, const optional<U>& y);
Mandates: The expression *x > *y is well-formed and its result is convertible to bool.
Returns: If !x, false; otherwise, if !y, true; otherwise *x > *y.
Remarks: Specializations of this function template for which *x > *y is a core constant expression are constexpr functions.
template<class T, class U> constexpr bool operator<=(const optional<T>& x, const optional<U>& y);
Mandates: The expression *x <= *y is well-formed and its result is convertible to bool.
Returns: If !x, true; otherwise, if !y, false; otherwise *x <= *y.
Remarks: Specializations of this function template for which *x <= *y is a core constant expression are constexpr functions.
template<class T, class U> constexpr bool operator>=(const optional<T>& x, const optional<U>& y);
Mandates: The expression *x >= *y is well-formed and its result is convertible to bool.
Returns: If !y, true; otherwise, if !x, false; otherwise *x >= *y.
Remarks: Specializations of this function template for which *x >= *y is a core constant expression are constexpr functions.
template<class T, three_way_comparable_with<T> U> constexpr compare_three_way_result_t<T, U> operator<=>(const optional<T>& x, const optional<U>& y);
Returns: If x && y, *x <=> *y; otherwise x.has_value() <=> y.has_value().
Remarks: Specializations of this function template for which *x <=> *y is a core constant expression are constexpr functions.

22.5.7 Comparison with nullopt [optional.nullops]

template<class T> constexpr bool operator==(const optional<T>& x, nullopt_t) noexcept;
Returns: !x.
template<class T> constexpr strong_ordering operator<=>(const optional<T>& x, nullopt_t) noexcept;
Returns: x.has_value() <=> false.

22.5.8 Comparison with T [optional.comp.with.t]

template<class T, class U> constexpr bool operator==(const optional<T>& x, const U& 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]
Effects: Equivalent to: return x.has_value() ? *x == v : false;
template<class T, class U> constexpr bool operator==(const T& v, const optional<U>& x);
Mandates: The expression v == *x is well-formed and its result is convertible to bool.
Effects: Equivalent to: return x.has_value() ? v == *x : false;
template<class T, class U> constexpr bool operator!=(const optional<T>& x, const U& v);
Mandates: The expression *x != v is well-formed and its result is convertible to bool.
Effects: Equivalent to: return x.has_value() ? *x != v : true;
template<class T, class U> constexpr bool operator!=(const T& v, const optional<U>& x);
Mandates: The expression v != *x is well-formed and its result is convertible to bool.
Effects: Equivalent to: return x.has_value() ? v != *x : true;
template<class T, class U> constexpr bool operator<(const optional<T>& x, const U& v);
Mandates: The expression *x < v is well-formed and its result is convertible to bool.
Effects: Equivalent to: return x.has_value() ? *x < v : true;
template<class T, class U> constexpr bool operator<(const T& v, const optional<U>& x);
Mandates: The expression v < *x is well-formed and its result is convertible to bool.
Effects: Equivalent to: return x.has_value() ? v < *x : false;
template<class T, class U> constexpr bool operator>(const optional<T>& x, const U& v);
Mandates: The expression *x > v is well-formed and its result is convertible to bool.
Effects: Equivalent to: return x.has_value() ? *x > v : false;
template<class T, class U> constexpr bool operator>(const T& v, const optional<U>& x);
Mandates: The expression v > *x is well-formed and its result is convertible to bool.
Effects: Equivalent to: return x.has_value() ? v > *x : true;
template<class T, class U> constexpr bool operator<=(const optional<T>& x, const U& v);
Mandates: The expression *x <= v is well-formed and its result is convertible to bool.
Effects: Equivalent to: return x.has_value() ? *x <= v : true;
template<class T, class U> constexpr bool operator<=(const T& v, const optional<U>& x);
Mandates: The expression v <= *x is well-formed and its result is convertible to bool.
Effects: Equivalent to: return x.has_value() ? v <= *x : false;
template<class T, class U> constexpr bool operator>=(const optional<T>& x, const U& v);
Mandates: The expression *x >= v is well-formed and its result is convertible to bool.
Effects: Equivalent to: return x.has_value() ? *x >= v : false;
template<class T, class U> constexpr bool operator>=(const T& v, const optional<U>& x);
Mandates: The expression v >= *x is well-formed and its result is convertible to bool.
Effects: Equivalent to: return x.has_value() ? v >= *x : true;
template<class T, class U> requires (!is-derived-from-optional<U>) && three_way_comparable_with<T, U> constexpr compare_three_way_result_t<T, U> operator<=>(const optional<T>& x, const U& v);
Effects: Equivalent to: return x.has_value() ? *x <=> v : strong_ordering​::​less;

22.5.9 Specialized algorithms [optional.specalg]

template<class T> constexpr void swap(optional<T>& x, optional<T>& y) noexcept(noexcept(x.swap(y)));
Constraints: is_move_constructible_v<T> is true and is_swappable_v<T> is true.
Effects: Calls x.swap(y).
template<class T> constexpr optional<decay_t<T>> make_optional(T&& v);
Returns: optional<decay_t<T>>(std​::​forward<T>(v)).
template<class T, class...Args> constexpr optional<T> make_optional(Args&&... args);
Effects: Equivalent to: return optional<T>(in_place, std​::​forward<Args>(args)...);
template<class T, class U, class... Args> constexpr optional<T> make_optional(initializer_list<U> il, Args&&... args);
Effects: Equivalent to: return optional<T>(in_place, il, std​::​forward<Args>(args)...);

22.5.10 Hash support [optional.hash]

template<class T> struct hash<optional<T>>;
The specialization hash<optional<T>> is enabled ([unord.hash]) if and only if hash<remove_const_t<T>> is enabled.
When enabled, for an object o of type optional<T>, if o.has_value() == true, then hash<optional<T>>()(o) evaluates to the same value as hash<remove_const_t<T>>()(*o); otherwise it evaluates to an unspecified value.
The member functions are not guaranteed to be noexcept.