60 KiB
[variant]
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 synopsis [variant.syn]
// mostly freestanding#include // see [compare.syn]namespace std {// [variant.variant], class template varianttemplate<class... Types>class variant; // [variant.helper], variant helper classestemplate struct variant_size; // not definedtemplate struct variant_size; templateconstexpr size_t variant_size_v = variant_size::value; template<class... Types>struct variant_size<variant<Types...>>; template<size_t I, class T> struct variant_alternative; // not definedtemplate<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 accesstemplate<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-deletedtemplate<size_t I, class... Types>constexpr variant_alternative_t<I, variant<Types...>>&& get(variant<Types...>&&); // freestanding-deletedtemplate<size_t I, class... Types>constexpr const variant_alternative_t<I, variant<Types...>>& get(const variant<Types...>&); // freestanding-deletedtemplate<size_t I, class... Types>constexpr const variant_alternative_t<I, variant<Types...>>&& get(const variant<Types...>&&); // freestanding-deletedtemplate<class T, class... Types>constexpr T& get(variant<Types...>&); // freestanding-deletedtemplate<class T, class... Types>constexpr T&& get(variant<Types...>&&); // freestanding-deletedtemplate<class T, class... Types>constexpr const T& get(const variant<Types...>&); // freestanding-deletedtemplate<class T, class... Types>constexpr const T&& get(const variant<Types...>&&); // freestanding-deletedtemplate<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 get_if(variant<Types...>) noexcept; template<class T, class... Types>constexpr add_pointer_t get_if(const variant<Types...>) noexcept; // [variant.relops], relational operatorstemplate<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 && ...)constexpr common_comparison_category_t<compare_three_way_result_t...>operator<=>(const variant<Types...>&, const variant<Types...>&); // [variant.visit], visitationtemplate<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 monostatestruct monostate; // [variant.monostate.relops], monostate relational operatorsconstexpr bool operator==(monostate, monostate) noexcept; constexpr strong_ordering operator<=>(monostate, monostate) noexcept; // [variant.specalg], specialized algorithmstemplate<class... Types>constexpr void swap(variant<Types...>&, variant<Types...>&) noexcept(see below); // [variant.bad.access], class bad_variant_accessclass bad_variant_access; // [variant.hash], hash supporttemplate struct hash; template<class... Types> struct hash<variant<Types...>>; template<> struct hash;}
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], constructorsconstexpr variant() noexcept(see below); constexpr variant(const variant&); constexpr variant(variant&&) noexcept(see below); templateconstexpr variant(T&&) noexcept(see below); template<class T, class... Args>constexpr explicit variant(in_place_type_t, Args&&...); template<class T, class U, class... Args>constexpr explicit variant(in_place_type_t, initializer_list, Args&&...); template<size_t I, class... Args>constexpr explicit variant(in_place_index_t, Args&&...); template<size_t I, class U, class... Args>constexpr explicit variant(in_place_index_t, initializer_list, Args&&...); // [variant.dtor], destructorconstexpr ~variant(); // [variant.assign], assignmentconstexpr variant& operator=(const variant&); constexpr variant& operator=(variant&&) noexcept(see below); template constexpr variant& operator=(T&&) noexcept(see below); // [variant.mod], modifierstemplate<class T, class... Args>constexpr T& emplace(Args&&...); template<class T, class U, class... Args>constexpr T& emplace(initializer_list, 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, Args&&...); // [variant.status], value statusconstexpr bool valueless_by_exception() const noexcept; constexpr size_t index() const noexcept; // [variant.swap], swapconstexpr void swap(variant&) noexcept(see below); // [variant.visit], visitationtemplate<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 nested within ([intro.object]) thevariant object.
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 Ti be the ith 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 T0.
Postconditions: valueless_by_exception() is false and index() is 0.
Throws: Any exception thrown by the value-initialization of T0.
Remarks: This function is constexpr if and only if the value-initialization of the alternative type T0 would be constexpr-suitable ([dcl.constexpr]).
The exception specification is equivalent tois_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(w), where j is w.index().
Otherwise, initializes the variant to not hold a value.
Throws: Any exception thrown by direct-initializing any Ti for all i.
Remarks: This constructor is defined as deleted unlessis_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 withGET(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 Ti for all i.
Remarks: The exception specification is equivalent to the logical and ofis_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 Tj be a type that is determined as follows: build an imaginary function FUN(Ti) for each alternative type Ti for which Ti x[] = {std::forward(t)}; is well-formed for some invented variable x.
The overload FUN(Tj) selected by overload resolution for the expression FUN(std::forward(t)) defines the alternative Tj which is the type of the contained value after construction.
Constraints:
sizeof...(Types) is nonzero,
is_same_v<remove_cvref_t, variant> is false,
remove_cvref_t is neither a specialization of in_place_type_t nor a specialization of in_place_index_t,
is_constructible_v<Tj, T> is true, and
the expression FUN(std::forward(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 Tj and direct-non-list-initializes the contained value with std::forward(t).
Postconditions: holds_alternative(*this) is true.
Throws: Any exception thrown by the initialization of the selected alternative Tj.
Remarks: The exception specification is equivalent tois_nothrow_constructible_v<Tj, T>.
If Tj'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)....
Postconditions: holds_alternative(*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&, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type T with il, std::forward(args)....
Postconditions: holds_alternative(*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<TI, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type TI with std::forward(args)....
Postconditions: index() is I.
Throws: Any exception thrown by calling the selected constructor of TI.
Remarks: If TI'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<TI, initializer_list&, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type TI with il, std::forward(args)....
Postconditions: index() is I.
Remarks: If TI'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 Ti, 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 oris_nothrow_move_constructible_v is false, equivalent to emplace(GET(rhs)).
-
Otherwise, equivalent to operator=(variant(rhs)).
Postconditions: index() == rhs.index().
Returns: *this.
Remarks: This operator is defined as deleted unlessis_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 istrue 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(std::move(rhs)) to the value contained in *this.
-
Otherwise, equivalent to emplace(GET(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 tois_nothrow_move_constructible_v && is_nothrow_move_assignable_v for all i.
-
If an exception is thrown during the call to Tj's move construction (with j being rhs.index()), the variant will hold no value.
-
If an exception is thrown during the call to Tj's move assignment, the state of the contained value is as defined by the exception safety guarantee of Tj's move assignment; index() will be j.
template<class T> constexpr variant& operator=(T&& t) noexcept(see below);
Let Tj be a type that is determined as follows: build an imaginary function FUN(Ti) for each alternative type Ti for which Ti x[] = {std::forward(t)}; is well-formed for some invented variable x.
The overload FUN(Tj) selected by overload resolution for the expression FUN(std::forward(t)) defines the alternative Tj which is the type of the contained value after assignment.
Constraints:
is_same_v<remove_cvref_t, variant> is false,
is_assignable_v<Tj&, T> && is_constructible_v<Tj, T> is true, and
the expression FUN(std::forward(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 Tj, assigns std::forward(t) to the value contained in *this.
-
Otherwise, if is_nothrow_constructible_v<Tj, T> ||!is_nothrow_move_constructible_v is true, equivalent to emplace(std::forward(t)).
-
Otherwise, equivalent to emplace(Tj(std::forward(t))).
Postconditions: holds_alternative(*this) is true, with Tj selected by the imaginary function overload resolution described above.
Returns: *this.
Remarks: The exception specification is equivalent to:is_nothrow_assignable_v<Tj&, T> && is_nothrow_constructible_v<Tj, T>
-
If an exception is thrown during the assignment of std::forward(t) to the value contained in *this, the state of the contained value andt 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, andT occurs exactly once in Types.
Effects: Equivalent to:return emplace(std::forward(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&, Args...> is true, and T occurs exactly once in Types.
Effects: Equivalent to:return emplace(il, std::forward(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<TI, 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 TI with the arguments std::forward(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<TI, initializer_list&, 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 TI with il, std::forward(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 avariant<float, int> can become valueless_by_exception(), for instance bystruct 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 Ti 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(*this), GET(rhs)) where i is index().
-
Otherwise, exchanges values of rhs and *this.
Throws: If index() == rhs.index(), any exception thrown by swap(GET(*this), GET(rhs)) with i being index().
Otherwise, any exception thrown by the move constructor of Ti or Tj with i being index() and j being rhs.index().
Remarks: If an exception is thrown during the call to function swap(GET(*this), GET(rhs)), the states of the contained values of *this and of rhs are determined by the exception safety guarantee of swap for lvalues ofTi 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 ofis_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 theCpp17UnaryTypeTrait 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 of the cv-unqualified type T.
Then each specialization of the template meets theCpp17UnaryTypeTrait 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 TI.
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(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(v) == GET(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(v) == GET(w) with i being v.index().
template<class... Types> constexpr bool operator!=(const variant<Types...>& v, const variant<Types...>& w);
Constraints: GET(v) != GET(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(v) != GET(w) with i being v.index().
template<class... Types> constexpr bool operator<(const variant<Types...>& v, const variant<Types...>& w);
Constraints: GET(v) < GET(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(v) < GET(w) with i being v.index().
template<class... Types> constexpr bool operator>(const variant<Types...>& v, const variant<Types...>& w);
Constraints: GET(v) > GET(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(v) > GET(w) with i being v.index().
template<class... Types> constexpr bool operator<=(const variant<Types...>& v, const variant<Types...>& w);
Constraints: GET(v) <= GET(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(v) <= GET(w) with i being v.index().
template<class... Types> constexpr bool operator>=(const variant<Types...>& v, const variant<Types...>& w);
Constraints: GET(v) >= GET(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(v) >= GET(w) with i being v.index().
template<class... Types> requires ([three_way_comparable](cmp.concept#concept:three_way_comparable "17.12.4 Concept three_way_comparable [cmp.concept]")<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(v) <=> GET(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 0â¤i<n, letVi denote the type
decltype(as-variant(std::forward(varsi))).
Constraints: Vi is a valid type for all 0â¤i<n.
Let V denote the pack of types Vi.
Let m be a pack of n values of type size_t.
Such a pack is valid if
0â¤mi<variant_size_v<remove_reference_t> for all 0â¤i<n.
For each valid pack m, let e(m) denote the expression:INVOKE(std::forward(vis), GET(std::forward(vars))...) // see [func.require] for the first form andINVOKE(std::forward(vis), GET(std::forward(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 whichmi is as-variant(varsi).index() for all 0â¤i<n.
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 n=1, it does not depend on the number of alternative types of V0.
For n>1, 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 beOVERRIDE_REF(Self&&, COPY_CONST(remove_reference_t, 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(vis), (V)self);
template<class R, class Self, class Visitor> constexpr R visit(this Self&& self, Visitor&& vis);
Let V beOVERRIDE_REF(Self&&, COPY_CONST(remove_reference_t, variant)) ([forward]).
Effects: Equivalent to: return std::visit(std::forward(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 functionsconstexpr 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.
constexpr const char* what() const noexcept override;
Returns: An implementation-defined ntbs, which during constant evaluation is encoded with the ordinary literal encoding ([lex.ccon]).
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>... is enabled.
The member functions are not guaranteed to be noexcept.
template<> struct hash<monostate>;
The specialization is enabled ([unord.hash]).