22 General utilities library [utilities]
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])
.
#include <compare>
namespace std {
template<class... Types>
class variant;
template<class T> struct variant_size;
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;
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;
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...>&);
template<size_t I, class... Types>
constexpr variant_alternative_t<I, variant<Types...>>&&
get(variant<Types...>&&);
template<size_t I, class... Types>
constexpr const variant_alternative_t<I, variant<Types...>>&
get(const variant<Types...>&);
template<size_t I, class... Types>
constexpr const variant_alternative_t<I, variant<Types...>>&&
get(const variant<Types...>&&);
template<class T, class... Types>
constexpr T& get(variant<Types...>&);
template<class T, class... Types>
constexpr T&& get(variant<Types...>&&);
template<class T, class... Types>
constexpr const T& get(const variant<Types...>&);
template<class T, class... Types>
constexpr const T&& get(const variant<Types...>&&);
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;
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...>&);
template<class Visitor, class... Variants>
constexpr see below visit(Visitor&&, Variants&&...);
template<class R, class Visitor, class... Variants>
constexpr R visit(Visitor&&, Variants&&...);
struct monostate;
constexpr bool operator==(monostate, monostate) noexcept;
constexpr strong_ordering operator<=>(monostate, monostate) noexcept;
template<class... Types>
constexpr void swap(variant<Types...>&, variant<Types...>&) noexcept(see below);
class bad_variant_access;
template<class T> struct hash;
template<class... Types> struct hash<variant<Types...>>;
template<> struct hash<monostate>;
}
namespace std {
template<class... Types>
class variant {
public:
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&&...);
constexpr ~variant();
constexpr variant& operator=(const variant&);
constexpr variant& operator=(variant&&) noexcept(see below);
template<class T> constexpr variant& operator=(T&&) noexcept(see below);
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&&...);
constexpr bool valueless_by_exception() const noexcept;
constexpr size_t index() const noexcept;
constexpr void swap(variant&) noexcept(see below);
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 nested within (
[intro.object]) the
variant object
.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
.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<T0> 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 to
is_nothrow_default_constructible_v<T0>. [
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
Ti for all
i. Remarks: This constructor is defined as deleted unless
is_copy_constructible_v<Ti> is
true for all
i. If
is_trivially_copy_constructible_v<Ti>
is
true for all
i, this constructor is trivial
.constexpr variant(variant&& w) noexcept(see below);
Constraints:
is_move_constructible_v<Ti> 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
Ti for all
i. Remarks: The exception specification is equivalent to the logical
and of
is_nothrow_move_constructible_v<Ti> for all
i. If
is_trivially_move_constructible_v<Ti>
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>(t)};
is well-formed for some invented variable
x. The overload
FUN(Tj) selected by overload
resolution for the expression
FUN(std::forward<T>(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<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<Tj, 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
Tj and
direct-non-list-initializes the contained value with
std::forward<T>(t). Postconditions:
holds_alternative<Tj>(*this) is
true. Throws: Any exception thrown by the initialization of the selected alternative
Tj. Remarks: The exception specification is equivalent to
is_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>(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<TI, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type
TI
with
std::forward<Args>(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<U>&, Args...> is true.
Effects: Direct-non-list-initializes the contained value of type
TI
with
il, std::forward<Args>(args).... Postconditions:
index() is
I. Remarks: If
TI's selected constructor is a constexpr constructor, this
constructor is a constexpr constructor
. Effects: If
valueless_by_exception() is
false,
destroys the currently contained value
. Remarks: If
is_trivially_destructible_v<Ti> is
true for all
Ti,
then this destructor is trivial
. constexpr variant& operator=(const variant& rhs);
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<Tj>
is
true or
is_nothrow_move_constructible_v<Tj> is
false,
equivalent to
emplace<j>(GET<j>(rhs)).Otherwise, equivalent to
operator=(variant(rhs)).
Postconditions:
index() == rhs.index(). Remarks: This operator is defined as deleted unless
is_copy_constructible_v<Ti> &&
is_copy_assignable_v<Ti>
is
true for all
i. If
is_trivially_copy_constructible_v<Ti> &&
is_trivially_copy_assignable_v<Ti> &&
is_trivially_destructible_v<Ti>
is
true for all
i, this assignment operator is trivial
.constexpr variant& operator=(variant&& rhs) noexcept(see below);
Constraints:
is_move_constructible_v<Ti> &&
is_move_assignable_v<Ti> 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))).
Remarks: If
is_trivially_move_constructible_v<Ti> &&
is_trivially_move_assignable_v<Ti> &&
is_trivially_destructible_v<Ti>
is
true for all
i, this assignment operator is trivial
. The exception specification is equivalent to
is_nothrow_move_constructible_v<Ti> && is_nothrow_move_assignable_v<Ti> 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>(t)};
is well-formed for some invented variable
x. The overload
FUN(Tj) selected by overload
resolution for the expression
FUN(std::forward<T>(t)) defines
the alternative
Tj which is the type of the contained value after
assignment
.Constraints:
- is_same_v<remove_cvref_t<T>, variant> is false,
- is_assignable_v<Tj&, T> && is_constructible_v<Tj, 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
Tj, assigns
std::forward<T>(t) to
the value contained in
*this.Otherwise, if
is_nothrow_constructible_v<Tj, T> ||
!is_nothrow_move_constructible_v<Tj> is
true,
equivalent to
emplace<j>(std::forward<T>(t)).Otherwise, equivalent to
emplace<j>(Tj(std::forward<T>(t))).
Postconditions:
holds_alternative<Tj>(*this) is
true, with
Tj
selected by the imaginary function overload resolution described above
. 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>(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
.
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<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>(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<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
TI
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
. 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
.constexpr void swap(variant& rhs) noexcept(see below);
Mandates:
is_move_constructible_v<Ti> is
true for all
i. 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
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<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
Ti 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<Ti> && is_nothrow_swappable_v<Ti> for all
i.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. variant_alternative<I, variant<Types...>>::type
Mandates:
I < sizeof...(Types). 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);
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). 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. 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(). 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, let
Vi denote the type
decltype(as-variant(std::forward<Variantsi>(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<Vi>>
for all
0≤i<n. For each valid pack
m, let
e(m) denote the expression:
INVOKE(std::forward<Visitor>(vis), GET<m>(std::forward<V>(vars))...)
for the first form and
INVOKE<R>(std::forward<Visitor>(vis), GET<m>(std::forward<V>(vars))...)
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
mi 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 be
OVERRIDE_REF(Self&&, COPY_CONST(remove_reference_t<Self>, variant)) (
[forward])
.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);
The class
monostate can serve as a first alternative type for
a
variant to make the
variant type default constructible
.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]
template<class... Types>
constexpr void swap(variant<Types...>& v, variant<Types...>& w) noexcept(see below);
Constraints:
is_move_constructible_v<Ti> && is_swappable_v<Ti>
is
true for all
i. Effects: Equivalent to
v.swap(w). Remarks: The exception specification is equivalent to
noexcept(v.swap(w)).
namespace std {
class bad_variant_access : public exception {
public:
constexpr 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])
. 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>;