22 General utilities library [utilities]

22.6 Variants [variant]

22.6.1 General [variant.general]

A variant object holds and manages the lifetime of a value.
If the variant holds a value, that value's type has to be one of the template argument types given to variant.
These template arguments are called alternatives.
In [variant], GET denotes a set of exposition-only function templates ([variant.get]).

22.6.2 Header <variant> synopsis [variant.syn]

// mostly freestanding #include <compare> // see [compare.syn] namespace std { // [variant.variant], class template variant template<class... Types> class variant; // [variant.helper], variant helper classes template<class T> struct variant_size; // not defined template<class T> struct variant_size<const T>; template<class T> constexpr size_t variant_size_v = variant_size<T>::value; template<class... Types> struct variant_size<variant<Types...>>; template<size_t I, class T> struct variant_alternative; // not defined template<size_t I, class T> struct variant_alternative<I, const T>; template<size_t I, class T> using variant_alternative_t = typename variant_alternative<I, T>::type; template<size_t I, class... Types> struct variant_alternative<I, variant<Types...>>; inline constexpr size_t variant_npos = -1; // [variant.get], value access template<class T, class... Types> constexpr bool holds_alternative(const variant<Types...>&) noexcept; template<size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>>& get(variant<Types...>&); // freestanding-deleted template<size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>>&& get(variant<Types...>&&); // freestanding-deleted template<size_t I, class... Types> constexpr const variant_alternative_t<I, variant<Types...>>& get(const variant<Types...>&); // freestanding-deleted template<size_t I, class... Types> constexpr const variant_alternative_t<I, variant<Types...>>&& get(const variant<Types...>&&); // freestanding-deleted template<class T, class... Types> constexpr T& get(variant<Types...>&); // freestanding-deleted template<class T, class... Types> constexpr T&& get(variant<Types...>&&); // freestanding-deleted template<class T, class... Types> constexpr const T& get(const variant<Types...>&); // freestanding-deleted template<class T, class... Types> constexpr const T&& get(const variant<Types...>&&); // freestanding-deleted template<size_t I, class... Types> constexpr add_pointer_t<variant_alternative_t<I, variant<Types...>>> get_if(variant<Types...>*) noexcept; template<size_t I, class... Types> constexpr add_pointer_t<const variant_alternative_t<I, variant<Types...>>> get_if(const variant<Types...>*) noexcept; template<class T, class... Types> constexpr add_pointer_t<T> get_if(variant<Types...>*) noexcept; template<class T, class... Types> constexpr add_pointer_t<const T> get_if(const variant<Types...>*) noexcept; // [variant.relops], relational operators template<class... Types> constexpr bool operator==(const variant<Types...>&, const variant<Types...>&); template<class... Types> constexpr bool operator!=(const variant<Types...>&, const variant<Types...>&); template<class... Types> constexpr bool operator<(const variant<Types...>&, const variant<Types...>&); template<class... Types> constexpr bool operator>(const variant<Types...>&, const variant<Types...>&); template<class... Types> constexpr bool operator<=(const variant<Types...>&, const variant<Types...>&); template<class... Types> constexpr bool operator>=(const variant<Types...>&, const variant<Types...>&); template<class... Types> requires (three_way_comparable<Types> && ...) constexpr common_comparison_category_t<compare_three_way_result_t<Types>...> operator<=>(const variant<Types...>&, const variant<Types...>&); // [variant.visit], visitation template<class Visitor, class... Variants> constexpr see below visit(Visitor&&, Variants&&...); template<class R, class Visitor, class... Variants> constexpr R visit(Visitor&&, Variants&&...); // [variant.monostate], class monostate struct monostate; // [variant.monostate.relops], monostate relational operators constexpr bool operator==(monostate, monostate) noexcept; constexpr strong_ordering operator<=>(monostate, monostate) noexcept; // [variant.specalg], specialized algorithms template<class... Types> constexpr void swap(variant<Types...>&, variant<Types...>&) noexcept(see below); // [variant.bad.access], class bad_variant_access class bad_variant_access; // [variant.hash], hash support template<class T> struct hash; template<class... Types> struct hash<variant<Types...>>; template<> struct hash<monostate>; }

22.6.3 Class template variant [variant.variant]

22.6.3.1 General [variant.variant.general]

namespace std { template<class... Types> class variant { public: // [variant.ctor], constructors constexpr variant() noexcept(see below); constexpr variant(const variant&); constexpr variant(variant&&) noexcept(see below); template<class T> constexpr variant(T&&) noexcept(see below); template<class T, class... Args> constexpr explicit variant(in_place_type_t<T>, Args&&...); template<class T, class U, class... Args> constexpr explicit variant(in_place_type_t<T>, initializer_list<U>, Args&&...); template<size_t I, class... Args> constexpr explicit variant(in_place_index_t<I>, Args&&...); template<size_t I, class U, class... Args> constexpr explicit variant(in_place_index_t<I>, initializer_list<U>, Args&&...); // [variant.dtor], destructor constexpr ~variant(); // [variant.assign], assignment constexpr variant& operator=(const variant&); constexpr variant& operator=(variant&&) noexcept(see below); template<class T> constexpr variant& operator=(T&&) noexcept(see below); // [variant.mod], modifiers template<class T, class... Args> constexpr T& emplace(Args&&...); template<class T, class U, class... Args> constexpr T& emplace(initializer_list<U>, Args&&...); template<size_t I, class... Args> constexpr variant_alternative_t<I, variant<Types...>>& emplace(Args&&...); template<size_t I, class U, class... Args> constexpr variant_alternative_t<I, variant<Types...>>& emplace(initializer_list<U>, Args&&...); // [variant.status], value status constexpr bool valueless_by_exception() const noexcept; constexpr size_t index() const noexcept; // [variant.swap], swap constexpr void swap(variant&) noexcept(see below); // [variant.visit], visitation template<class Self, class Visitor> constexpr decltype(auto) visit(this Self&&, Visitor&&); template<class R, class Self, class Visitor> constexpr R visit(this Self&&, Visitor&&); }; }
Any instance of variant at any given time either holds a value of one of its alternative types or holds no value.
When an instance of variant holds a value of alternative type T, it means that a value of type T, referred to as the variant object's contained value, is allocated within the storage of the variant object.
Implementations are not permitted to use additional storage, such as dynamic memory, to allocate the contained value.
All types in Types shall meet the Cpp17Destructible requirements (Table 35).
A program that instantiates the definition of variant with no template arguments is ill-formed.
If a program declares an explicit or partial specialization of variant, the program is ill-formed, no diagnostic required.

22.6.3.2 Constructors [variant.ctor]

In the descriptions that follow, let i be in the range [0, sizeof...(Types)), and be the type in Types.
constexpr variant() noexcept(see below);
Constraints: is_default_constructible_v<> is true.
Effects: Constructs a variant holding a value-initialized value of type .
Postconditions: valueless_by_exception() is false and index() is 0.
Throws: Any exception thrown by the value-initialization of .
Remarks: This function is constexpr if and only if the value-initialization of the alternative type would be constexpr-suitable ([dcl.constexpr]).
The exception specification is equivalent to is_nothrow_default_constructible_v<>.
[Note 1: 
See also class monostate.
— end note]
constexpr variant(const variant& w);
Effects: If w holds a value, initializes the variant to hold the same alternative as w and direct-initializes the contained value with GET<j>(w), where j is w.index().
Otherwise, initializes the variant to not hold a value.
Throws: Any exception thrown by direct-initializing any for all i.
Remarks: This constructor is defined as deleted unless is_copy_constructible_v<> is true for all i.
If is_trivially_copy_constructible_v<> is true for all i, this constructor is trivial.
constexpr variant(variant&& w) noexcept(see below);
Constraints: is_move_constructible_v<> is true for all i.
Effects: If w holds a value, initializes the variant to hold the same alternative as w and direct-initializes the contained value with GET<j>(std​::​move(w)), where j is w.index().
Otherwise, initializes the variant to not hold a value.
Throws: Any exception thrown by move-constructing any for all i.
Remarks: The exception specification is equivalent to the logical and of is_nothrow_move_constructible_v<> for all i.
If is_trivially_move_constructible_v<> is true for all i, this constructor is trivial.
template<class T> constexpr variant(T&& t) noexcept(see below);
Let be a type that is determined as follows: build an imaginary function FUN() for each alternative type for which x[] = {std​::​forward<T>(t)}; is well-formed for some invented variable x.
The overload FUN() selected by overload resolution for the expression FUN(std​::​forward<T>(​t)) defines the alternative which is the type of the contained value after construction.
Constraints:
  • sizeof...(Types) is nonzero,
  • is_same_v<remove_cvref_t<T>, variant> is false,
  • remove_cvref_t<T> is neither a specialization of in_place_type_t nor a specialization of in_place_index_t,
  • is_constructible_v<, T> is true, and
  • the expression FUN(std​::​forward<T>(t)) (with FUN being the above-mentioned set of imaginary functions) is well-formed.
    [Note 2: 
    variant<string, string> v("abc"); is ill-formed, as both alternative types have an equally viable constructor for the argument.
    — end note]
Effects: Initializes *this to hold the alternative type and direct-non-list-initializes the contained value with std​::​forward<T>(t).
Postconditions: holds_alternative<>(*this) is true.
Throws: Any exception thrown by the initialization of the selected alternative .
Remarks: The exception specification is equivalent to is_nothrow_constructible_v<, T>.
If 's selected constructor is a constexpr constructor, this constructor is a constexpr constructor.
template<class T, class... Args> constexpr explicit variant(in_place_type_t<T>, Args&&... args);
Constraints:
  • There is exactly one occurrence of T in Types... and
  • is_constructible_v<T, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type T with std​::​forward<Args>(args)....
Postconditions: holds_alternative<T>(*this) is true.
Throws: Any exception thrown by calling the selected constructor of T.
Remarks: If T's selected constructor is a constexpr constructor, this constructor is a constexpr constructor.
template<class T, class U, class... Args> constexpr explicit variant(in_place_type_t<T>, initializer_list<U> il, Args&&... args);
Constraints:
  • There is exactly one occurrence of T in Types... and
  • is_constructible_v<T, initializer_list<U>&, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type T with il, std​::​forward<Args>(​args)....
Postconditions: holds_alternative<T>(*this) is true.
Throws: Any exception thrown by calling the selected constructor of T.
Remarks: If T's selected constructor is a constexpr constructor, this constructor is a constexpr constructor.
template<size_t I, class... Args> constexpr explicit variant(in_place_index_t<I>, Args&&... args);
Constraints:
  • I is less than sizeof...(Types) and
  • is_constructible_v<, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type with std​::​forward<Args>(args)....
Postconditions: index() is I.
Throws: Any exception thrown by calling the selected constructor of .
Remarks: If 's selected constructor is a constexpr constructor, this constructor is a constexpr constructor.
template<size_t I, class U, class... Args> constexpr explicit variant(in_place_index_t<I>, initializer_list<U> il, Args&&... args);
Constraints:
  • I is less than sizeof...(Types) and
  • is_constructible_v<, initializer_list<U>&, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type with il, std​::​forward<Args>(​args)....
Postconditions: index() is I.
Remarks: If 's selected constructor is a constexpr constructor, this constructor is a constexpr constructor.

22.6.3.3 Destructor [variant.dtor]

constexpr ~variant();
Effects: If valueless_by_exception() is false, destroys the currently contained value.
Remarks: If is_trivially_destructible_v<> is true for all , then this destructor is trivial.

22.6.3.4 Assignment [variant.assign]

constexpr variant& operator=(const variant& rhs);
Let j be rhs.index().
Effects:
  • If neither *this nor rhs holds a value, there is no effect.
  • Otherwise, if *this holds a value but rhs does not, destroys the value contained in *this and sets *this to not hold a value.
  • Otherwise, if index() == j, assigns the value contained in rhs to the value contained in *this.
  • Otherwise, if either is_nothrow_copy_constructible_v<> is true or is_nothrow_move_constructible_v<> is false, equivalent to emplace<j>(GET<j>(rhs)).
  • Otherwise, equivalent to operator=(variant(rhs)).
Postconditions: index() == rhs.index().
Returns: *this.
Remarks: This operator is defined as deleted unless is_copy_constructible_v<> && is_copy_assignable_v<> is true for all i.
If is_trivially_copy_constructible_v<> && is_trivially_copy_assignable_v<> && is_trivially_destructible_v<> is true for all i, this assignment operator is trivial.
constexpr variant& operator=(variant&& rhs) noexcept(see below);
Let j be rhs.index().
Constraints: is_move_constructible_v<> && is_move_assignable_v<> is true for all i.
Effects:
  • If neither *this nor rhs holds a value, there is no effect.
  • Otherwise, if *this holds a value but rhs does not, destroys the value contained in *this and sets *this to not hold a value.
  • Otherwise, if index() == j, assigns GET<j>(std​::​move(rhs)) to the value contained in *this.
  • Otherwise, equivalent to emplace<j>(GET<j>(std​::​move(rhs))).
Returns: *this.
Remarks: If is_trivially_move_constructible_v<> && is_trivially_move_assignable_v<> && is_trivially_destructible_v<> is true for all i, this assignment operator is trivial.
The exception specification is equivalent to is_nothrow_move_constructible_v<> && is_nothrow_move_assignable_v<> for all i.
  • If an exception is thrown during the call to 's move construction (with j being rhs.index()), the variant will hold no value.
  • If an exception is thrown during the call to 's move assignment, the state of the contained value is as defined by the exception safety guarantee of 's move assignment; index() will be j.
template<class T> constexpr variant& operator=(T&& t) noexcept(see below);
Let be a type that is determined as follows: build an imaginary function FUN() for each alternative type for which x[] = {std​::​forward<T>(t)}; is well-formed for some invented variable x.
The overload FUN() selected by overload resolution for the expression FUN(std​::​forward<T>(​t)) defines the alternative which is the type of the contained value after assignment.
Constraints:
  • is_same_v<remove_cvref_t<T>, variant> is false,
  • is_assignable_v<&, T> && is_constructible_v<, T> is true, and
  • the expression FUN(std​::​forward<T>(t)) (with FUN being the above-mentioned set of imaginary functions) is well-formed.
    [Note 1: 
    variant<string, string> v; v = "abc"; is ill-formed, as both alternative types have an equally viable constructor for the argument.
    — end note]
Effects:
  • If *this holds a , assigns std​::​forward<T>(t) to the value contained in *this.
  • Otherwise, if is_nothrow_constructible_v<, T> || !is_nothrow_move_constructible_v<> is true, equivalent to emplace<j>(std​::​forward<T>(t)).
  • Otherwise, equivalent to emplace<j>((std​::​forward<T>(t))).
Postconditions: holds_alternative<>(*this) is true, with selected by the imaginary function overload resolution described above.
Returns: *this.
Remarks: The exception specification is equivalent to: is_nothrow_assignable_v<T&, T> && is_nothrow_constructible_v<T, T>
  • If an exception is thrown during the assignment of std​::​forward<T>(t) to the value contained in *this, the state of the contained value and t are as defined by the exception safety guarantee of the assignment expression; valueless_by_exception() will be false.
  • If an exception is thrown during the initialization of the contained value, the variant object is permitted to not hold a value.

22.6.3.5 Modifiers [variant.mod]

template<class T, class... Args> constexpr T& emplace(Args&&... args);
Constraints: is_constructible_v<T, Args...> is true, and T occurs exactly once in Types.
Effects: Equivalent to: return emplace<I>(std::forward<Args>(args)...); where I is the zero-based index of T in Types.
template<class T, class U, class... Args> constexpr T& emplace(initializer_list<U> il, Args&&... args);
Constraints: is_constructible_v<T, initializer_list<U>&, Args...> is true, and T occurs exactly once in Types.
Effects: Equivalent to: return emplace<I>(il, std::forward<Args>(args)...); where I is the zero-based index of T in Types.
template<size_t I, class... Args> constexpr variant_alternative_t<I, variant<Types...>>& emplace(Args&&... args);
Mandates: I < sizeof...(Types).
Constraints: is_constructible_v<, Args...> is true.
Effects: Destroys the currently contained value if valueless_by_exception() is false.
Then direct-non-list-initializes the contained value of type with the arguments std​::​forward<Args>(args)....
Postconditions: index() is I.
Returns: A reference to the new contained value.
Throws: Any exception thrown during the initialization of the contained value.
Remarks: If an exception is thrown during the initialization of the contained value, the variant is permitted to not hold a value.
template<size_t I, class U, class... Args> constexpr variant_alternative_t<I, variant<Types...>>& emplace(initializer_list<U> il, Args&&... args);
Mandates: I < sizeof...(Types).
Constraints: is_constructible_v<, initializer_list<U>&, Args...> is true.
Effects: Destroys the currently contained value if valueless_by_exception() is false.
Then direct-non-list-initializes the contained value of type with il, std​::​forward<Args>(args)....
Postconditions: index() is I.
Returns: A reference to the new contained value.
Throws: Any exception thrown during the initialization of the contained value.
Remarks: If an exception is thrown during the initialization of the contained value, the variant is permitted to not hold a value.

22.6.3.6 Value status [variant.status]

constexpr bool valueless_by_exception() const noexcept;
Effects: Returns false if and only if the variant holds a value.
[Note 1: 
It is possible for a variant to hold no value if an exception is thrown during a type-changing assignment or emplacement.
The latter means that even a variant<float, int> can become valueless_by_exception(), for instance by struct S { operator int() { throw 42; }}; variant<float, int> v{12.f}; v.emplace<1>(S());
— end note]
constexpr size_t index() const noexcept;
Effects: If valueless_by_exception() is true, returns variant_npos.
Otherwise, returns the zero-based index of the alternative of the contained value.

22.6.3.7 Swap [variant.swap]

constexpr void swap(variant& rhs) noexcept(see below);
Mandates: is_move_constructible_v<> is true for all i.
Preconditions: Each meets the Cpp17Swappable requirements ([swappable.requirements]).
Effects:
  • If valueless_by_exception() && rhs.valueless_by_exception() no effect.
  • Otherwise, if index() == rhs.index(), calls swap(GET<i>(*this), GET<i>(rhs)) where i is index().
  • Otherwise, exchanges values of rhs and *this.
Throws: If index() == rhs.index(), any exception thrown by swap(GET<i>(*this), GET<i>(rhs)) with i being index().
Otherwise, any exception thrown by the move constructor of or with i being index() and j being rhs.index().
Remarks: If an exception is thrown during the call to function swap(GET<i>(*this), GET<i>(rhs)), the states of the contained values of *this and of rhs are determined by the exception safety guarantee of swap for lvalues of with i being index().
If an exception is thrown during the exchange of the values of *this and rhs, the states of the values of *this and of rhs are determined by the exception safety guarantee of variant's move constructor.
The exception specification is equivalent to the logical and of is_nothrow_move_constructible_v<> && is_nothrow_swappable_v<> for all i.

22.6.4 variant helper classes [variant.helper]

template<class T> struct variant_size;
All specializations of variant_size meet the Cpp17UnaryTypeTrait requirements ([meta.rqmts]) with a base characteristic of integral_constant<size_t, N> for some N.
template<class T> struct variant_size<const T>;
Let VS denote variant_size<T> of the cv-unqualified type T.
Then each specialization of the template meets the Cpp17UnaryTypeTrait requirements ([meta.rqmts]) with a base characteristic of integral_constant<size_t, VS​::​value>.
template<class... Types> struct variant_size<variant<Types...>> : integral_constant<size_t, sizeof...(Types)> { };
template<size_t I, class T> struct variant_alternative<I, const T>;
Let VA denote variant_alternative<I, T> of the cv-unqualified type T.
Then each specialization of the template meets the Cpp17TransformationTrait requirements ([meta.rqmts]) with a member typedef type that names the type add_const_t<VA​::​type>.
variant_alternative<I, variant<Types...>>::type
Mandates: I < sizeof...(Types).
Type: The type .

22.6.5 Value access [variant.get]

template<class T, class... Types> constexpr bool holds_alternative(const variant<Types...>& v) noexcept;
Mandates: The type T occurs exactly once in Types.
Returns: true if index() is equal to the zero-based index of T in Types.
template<size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>>& GET(variant<Types...>& v); // exposition only template<size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>>&& GET(variant<Types...>&& v); // exposition only template<size_t I, class... Types> constexpr const variant_alternative_t<I, variant<Types...>>& GET(const variant<Types...>& v); // exposition only template<size_t I, class... Types> constexpr const variant_alternative_t<I, variant<Types...>>&& GET(const variant<Types...>&& v); // exposition only
Mandates: I < sizeof...(Types).
Preconditions: v.index() is I.
Returns: A reference to the object stored in the variant.
template<size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>>& get(variant<Types...>& v); template<size_t I, class... Types> constexpr variant_alternative_t<I, variant<Types...>>&& get(variant<Types...>&& v); template<size_t I, class... Types> constexpr const variant_alternative_t<I, variant<Types...>>& get(const variant<Types...>& v); template<size_t I, class... Types> constexpr const variant_alternative_t<I, variant<Types...>>&& get(const variant<Types...>&& v);
Mandates: I < sizeof...(Types).
Effects: If v.index() is I, returns a reference to the object stored in the variant.
Otherwise, throws an exception of type bad_variant_access.
template<class T, class... Types> constexpr T& get(variant<Types...>& v); template<class T, class... Types> constexpr T&& get(variant<Types...>&& v); template<class T, class... Types> constexpr const T& get(const variant<Types...>& v); template<class T, class... Types> constexpr const T&& get(const variant<Types...>&& v);
Mandates: The type T occurs exactly once in Types.
Effects: If v holds a value of type T, returns a reference to that value.
Otherwise, throws an exception of type bad_variant_access.
template<size_t I, class... Types> constexpr add_pointer_t<variant_alternative_t<I, variant<Types...>>> get_if(variant<Types...>* v) noexcept; template<size_t I, class... Types> constexpr add_pointer_t<const variant_alternative_t<I, variant<Types...>>> get_if(const variant<Types...>* v) noexcept;
Mandates: I < sizeof...(Types).
Returns: A pointer to the value stored in the variant, if v != nullptr and v->index() == I.
Otherwise, returns nullptr.
template<class T, class... Types> constexpr add_pointer_t<T> get_if(variant<Types...>* v) noexcept; template<class T, class... Types> constexpr add_pointer_t<const T> get_if(const variant<Types...>* v) noexcept;
Mandates: The type T occurs exactly once in Types.
Effects: Equivalent to: return get_if<i>(v); with i being the zero-based index of T in Types.

22.6.6 Relational operators [variant.relops]

template<class... Types> constexpr bool operator==(const variant<Types...>& v, const variant<Types...>& w);
Constraints: GET<i>(v) == GET<i>(w) is a valid expression that is convertible to bool, for all i.
Returns: If v.index() != w.index(), false; otherwise if v.valueless_by_exception(), true; otherwise GET<i>(v) == GET<i>(w) with i being v.index().
template<class... Types> constexpr bool operator!=(const variant<Types...>& v, const variant<Types...>& w);
Constraints: GET<i>(v) != GET<i>(w) is a valid expression that is convertible to bool, for all i.
Returns: If v.index() != w.index(), true; otherwise if v.valueless_by_exception(), false; otherwise GET<i>(v) != GET<i>(w) with i being v.index().
template<class... Types> constexpr bool operator<(const variant<Types...>& v, const variant<Types...>& w);
Constraints: GET<i>(v) < GET<i>(w) is a valid expression that is convertible to bool, for all i.
Returns: If w.valueless_by_exception(), false; otherwise if v.valueless_by_exception(), true; otherwise, if v.index() < w.index(), true; otherwise if v.index() > w.index(), false; otherwise GET<i>(v) < GET<i>(w) with i being v.index().
template<class... Types> constexpr bool operator>(const variant<Types...>& v, const variant<Types...>& w);
Constraints: GET<i>(v) > GET<i>(w) is a valid expression that is convertible to bool, for all i.
Returns: If v.valueless_by_exception(), false; otherwise if w.valueless_by_exception(), true; otherwise, if v.index() > w.index(), true; otherwise if v.index() < w.index(), false; otherwise GET<i>(v) > GET<i>(w) with i being v.index().
template<class... Types> constexpr bool operator<=(const variant<Types...>& v, const variant<Types...>& w);
Constraints: GET<i>(v) <= GET<i>(w) is a valid expression that is convertible to bool, for all i.
Returns: If v.valueless_by_exception(), true; otherwise if w.valueless_by_exception(), false; otherwise, if v.index() < w.index(), true; otherwise if v.index() > w.index(), false; otherwise GET<i>(v) <= GET<i>(w) with i being v.index().
template<class... Types> constexpr bool operator>=(const variant<Types...>& v, const variant<Types...>& w);
Constraints: GET<i>(v) >= GET<i>(w) is a valid expression that is convertible to bool, for all i.
Returns: If w.valueless_by_exception(), true; otherwise if v.valueless_by_exception(), false; otherwise, if v.index() > w.index(), true; otherwise if v.index() < w.index(), false; otherwise GET<i>(v) >= GET<i>(w) with i being v.index().
template<class... Types> requires (three_way_comparable<Types> && ...) constexpr common_comparison_category_t<compare_three_way_result_t<Types>...> operator<=>(const variant<Types...>& v, const variant<Types...>& w);
Effects: Equivalent to: if (v.valueless_by_exception() && w.valueless_by_exception()) return strong_ordering::equal; if (v.valueless_by_exception()) return strong_ordering::less; if (w.valueless_by_exception()) return strong_ordering::greater; if (auto c = v.index() <=> w.index(); c != 0) return c; return GET<i>(v) <=> GET<i>(w); with i being v.index().

22.6.7 Visitation [variant.visit]

template<class Visitor, class... Variants> constexpr see below visit(Visitor&& vis, Variants&&... vars); template<class R, class Visitor, class... Variants> constexpr R visit(Visitor&& vis, Variants&&... vars);
Let as-variant denote the following exposition-only function templates: template<class... Ts> constexpr auto&& as-variant(variant<Ts...>& var) { return var; } template<class... Ts> constexpr auto&& as-variant(const variant<Ts...>& var) { return var; } template<class... Ts> constexpr auto&& as-variant(variant<Ts...>&& var) { return std::move(var); } template<class... Ts> constexpr auto&& as-variant(const variant<Ts...>&& var) { return std::move(var); }
Let n be sizeof...(Variants).
For each , let denote the type
decltype(as-variant(std​::​forward<>())).
Constraints: is a valid type for all .
Let V denote the pack of types .
Let m be a pack of n values of type size_t.
Such a pack is valid if
for all .
For each valid pack m, let e(m) denote the expression: INVOKE(std::forward<Visitor>(vis), GET<m>(std::forward<V>(vars))...) // see [func.require] for the first form and INVOKE<R>(std::forward<Visitor>(vis), GET<m>(std::forward<V>(vars))...) // see [func.require] for the second form.
Mandates: For each valid pack m, e(m) is a valid expression.
All such expressions are of the same type and value category.
Returns: e(m), where m is the pack for which is as-variant(vars).index() for all .
The return type is decltype(e(m)) for the first form.
Throws: bad_variant_access if (as-variant(vars).valueless_by_exception() || ...) is true.
Complexity: For n  ≤ 1, the invocation of the callable object is implemented in constant time, i.e., for , it does not depend on the number of alternative types of .
For , the invocation of the callable object has no complexity requirements.
template<class Self, class Visitor> constexpr decltype(auto) visit(this Self&& self, Visitor&& vis);
Let V be OVERRIDE_REF(Self&&, COPY_CONST(remove_reference_t<Self>, variant)) ([forward]).
Constraints: The call to visit does not use an explicit template-argument-list that begins with a type template-argument.
Effects: Equivalent to: return std​::​visit(std​::​forward<Visitor>(vis), (V)self);
template<class R, class Self, class Visitor> constexpr R visit(this Self&& self, Visitor&& vis);
Let V be OVERRIDE_REF(Self&&, COPY_CONST(remove_reference_t<Self>, variant)) ([forward]).
Effects: Equivalent to: return std​::​visit<R>(std​::​forward<Visitor>(vis), (V)self);

22.6.8 Class monostate [variant.monostate]

struct monostate{};
The class monostate can serve as a first alternative type for a variant to make the variant type default constructible.

22.6.9 monostate relational operators [variant.monostate.relops]

constexpr bool operator==(monostate, monostate) noexcept { return true; } constexpr strong_ordering operator<=>(monostate, monostate) noexcept { return strong_ordering::equal; }
[Note 1: 
monostate objects have only a single state; they thus always compare equal.
— end note]

22.6.10 Specialized algorithms [variant.specalg]

template<class... Types> constexpr void swap(variant<Types...>& v, variant<Types...>& w) noexcept(see below);
Constraints: is_move_constructible_v<> && is_swappable_v<> is true for all i.
Effects: Equivalent to v.swap(w).
Remarks: The exception specification is equivalent to noexcept(v.swap(w)).

22.6.11 Class bad_variant_access [variant.bad.access]

namespace std { class bad_variant_access : public exception { public: // see [exception] for the specification of the special member functions const char* what() const noexcept override; }; }
Objects of type bad_variant_access are thrown to report invalid accesses to the value of a variant object.
const char* what() const noexcept override;
Returns: An implementation-defined ntbs.

22.6.12 Hash support [variant.hash]

template<class... Types> struct hash<variant<Types...>>;
The specialization hash<variant<Types...>> is enabled ([unord.hash]) if and only if every specialization in hash<remove_const_t<Types>>... is enabled.
The member functions are not guaranteed to be noexcept.
template<> struct hash<monostate>;
The specialization is enabled ([unord.hash]).