namespace eggs { namespace variants { // variant for object types template <class ...Ts> class variant; // In-place construction template <std::size_t I> using in_place_index_t = void(*)(unspecified<I>); template <class T> using in_place_type_t = void(*)(unspecified<T>); template <std::size_t I> void in_place(unspecified<I>); template <class T> void in_place(unspecified<T>); // Class bad_variant_access class bad_variant_access; // Class template variant template <class ...Ts> class variant { public: static constexpr std::size_t npos = std::size_t(-1); // Constructors constexpr variant() noexcept; constexpr variant(variant const&); constexpr variant(variant&&) noexcept(see below); template <class U> constexpr variant(U&&); template <class U> constexpr explicit variant(U&&); template <std::size_t I, class ...Args> constexpr explicit variant(in_place_index_t<I>, Args&&...); template <std::size_t I, class U, class ...Args> constexpr explicit variant(in_place_index_t<I>, std::initializer_list<U>, Args&&...); 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>, std::initializer_list<U>, Args&&...); // Destructor ~variant(); // Assignment constexpr variant& operator=(variant const&); constexpr variant& operator=(variant&&) noexcept(see below); template <class U> constexpr variant& operator=(U&&); template <std::size_t I, class ...Args> constexpr T& emplace(Args&&...); template <std::size_t I, class U, class ...Args> constexpr T& emplace(std::initializer_list<U>, Args&&...); template <class T, class ...Args> constexpr T& emplace(Args&&...); template <class T, class U, class ...Args> constexpr T& emplace(std::initializer_list<U>, Args&&...); // Swap constexpr void swap(variant&) noexcept(see below); // Observers constexpr explicit operator bool() const noexcept; constexpr std::size_t which() const noexcept; constexpr std::type_info const& target_type() const noexcept; constexpr void* target() noexcept; constexpr void const* target() const noexcept; template <class T> constexpr T* target() noexcept; template <class T> constexpr T const* target() const noexcept; }; // Class bad_variant_access class bad_variant_access : public std::exception { public: bad_variant_access() noexcept; char const* what() const noexcept override; }; // Helper classes template <class T> struct variant_size; template <class ...Ts> struct variant_size<variant<Ts...>>; template <class T> struct variant_size<T const>; template <class T> inline constexpr std::size_t variant_size_v = variant_size<T>::value; template <std::size_t I, class T> struct variant_element; // undefined template <std::size_t I, class ...Ts> struct variant_element<I, variant<Ts...>>; template <std::size_t I, class T> struct variant_element<I, T const>; template <std::size_t I, class T> using variant_element_t = class variant_element<I, T>::type; // Element access template <std::size_t I, class ...Ts> constexpr variant_element_t<I, variant<Ts...>>& get(variant<Ts...>&); template <std::size_t I, class ...Ts> constexpr variant_element_t<I, variant<Ts...>> const& get(variant<Ts...> const&); template <std::size_t I, class ...Ts> constexpr variant_element_t<I, variant<Ts...>>&& get(variant<Ts...>&&); template <std::size_t I, class ...Ts> constexpr variant_element_t<I, variant<Ts...>> const&& get(variant<Ts...> const&&); template <class T, class ...Ts> constexpr T& get(variant<Ts...>&); template <class T, class ...Ts> constexpr T const& get(variant<Ts...> const&); template <class T, class ...Ts> constexpr T&& get(variant<Ts...>&&); template <class T, class ...Ts> constexpr T const&& get(variant<Ts...> const&&); template <std::size_t I, class ...Ts> constexpr variant_element_t<I, variant<Ts...>>* get_if(variant<Ts...>*) noexcept; template <std::size_t I, class ...Ts> constexpr variant_element_t<I, variant<Ts...>> const* get_if(variant<Ts...> const*) noexcept; template <class T, class ...Ts> constexpr T* get_if(variant<Ts...>*) noexcept; template <class T, class ...Ts> constexpr T const* get_if(variant<Ts...> const*) noexcept; // Relational operators template <class ...Ts> constexpr bool operator==(variant<Ts...> const&, variant<Ts...> const&); template <class ...Ts> constexpr bool operator!=(variant<Ts...> const&, variant<Ts...> const&); template <class ...Ts> constexpr bool operator<(variant<Ts...> const&, variant<Ts...> const&); template <class ...Ts> constexpr bool operator>(variant<Ts...> const&, variant<Ts...> const&); template <class ...Ts> constexpr bool operator<=(variant<Ts...> const&, variant<Ts...> const&); template <class ...Ts> constexpr bool operator>=(variant<Ts...> const&, variant<Ts...> const&); // Comparison with Ts template <class ...Ts, class U> constexpr bool operator==(variant<Ts...> const&, U const&); template <class U, class ...Ts> constexpr bool operator==(U const&, variant<Ts...> const&); template <class ...Ts, class U> constexpr bool operator!=(variant<Ts...> const&, U const&); template <class U, class ...Ts> constexpr bool operator!=(U const&, variant<Ts...> const&); template <class ...Ts, class U> constexpr bool operator<(variant<Ts...> const&, U const&); template <class U, class ...Ts> constexpr bool operator<(U const&, variant<Ts...> const&); template <class ...Ts, class U> constexpr bool operator>(variant<Ts...> const&, U const&); template <class U, class ...Ts> constexpr bool operator>(U const&, variant<Ts...> const&); template <class ...Ts, class U> constexpr bool operator<=(variant<Ts...> const&, U const&); template <class U, class ...Ts> constexpr bool operator<=(U const&, variant<Ts...> const&); template <class ...Ts, class U> constexpr bool operator>=(variant<Ts...> const&, U const&); template <class U, class ...Ts> constexpr bool operator>=(U const&, variant<Ts...> const&); // Calling a function with variants of arguments template <class R, class F, class ...Vs> constexpr R apply(F&&, Vs&&...); template <class F, class ...Vs> constexpr see below apply(F&&, Vs&&...); // Specialized algorithms template <class ...Ts> constexpr void swap(variant<Ts...>&, variant<Ts...>&) noexcept(see below); }} // Hash support namespace std { template <class ...Ts> struct hash<::eggs::variants::variant<Ts...>>; } namespace eggs { using variants::variant; using variants::variant_size; using variants::variant_size_v; using variants::variant_element; using variants::variant_element_t; constexpr std::size_t variant_npos = std::size_t(-1); using variants::bad_variant_access; using variants::get; using variants::get_if; using variants::apply; }
variant
template <class ...Ts> class variant { public: static constexpr std::size_t npos = std::size_t(-1); // Constructors constexpr variant() noexcept; constexpr variant(variant const&); constexpr variant(variant&&) noexcept(see below); template <class U> constexpr variant(U&&); template <class U> constexpr explicit variant(U&&); template <std::size_t I, class ...Args> constexpr explicit variant(in_place_index_t<I>, Args&&...); template <std::size_t I, class U, class ...Args> constexpr explicit variant(in_place_index_t<I>, std::initializer_list<U>, Args&&...); 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>, std::initializer_list<U>, Args&&...); // Destructor ~variant(); // Assignment constexpr variant& operator=(variant const&); constexpr variant& operator=(variant&&) noexcept(see below); template <class U> constexpr variant& operator=(U&&); template <std::size_t I, class ...Args> constexpr T& emplace(Args&&...); template <std::size_t I, class U, class ...Args> constexpr T& emplace(std::initializer_list<U>, Args&&...); template <class T, class ...Args> constexpr T& emplace(Args&&...); template <class T, class U, class ...Args> constexpr T& emplace(std::initializer_list<U>, Args&&...); // Swap constexpr void swap(variant&) noexcept(see below); // Observers constexpr explicit operator bool() const noexcept; constexpr std::size_t which() const noexcept; constexpr std::type_info const& target_type() const noexcept; constexpr void* target() noexcept; constexpr void const* target() const noexcept; template <class T> constexpr T* target() noexcept; template <class T> constexpr T const* target() const noexcept; };
In a variant
, at most one of the members can be active at any time, that is, the value of at most one of the members can be stored in a variant
at any time. Implementations are not permitted to use additional storage, such as dynamic memory, to allocate its contained value. The contained value shall be allocated in a region of the variant<Ts...>
storage suitably aligned for the types Ts...
.
All T
in Ts...
shall be object types and shall satisfy the requirements of Destructible
.
constexpr variant() noexcept;
*this
does not have an active member.Ts...
this constructor shall be a constexpr
constructor.constexpr variant(variant const& rhs);
rhs
has an active member of type T
, initializes the active member as if direct-non-list-initializing an object of type T
with the expression *rhs.target<T>()
; otherwise, no member is initialized.rhs.which() == this->which()
.T
.std::is_copy_constructible_v<T>
is true
for all T
in Ts...
. If std::is_trivially_copyable_v<T>
is true
for all T
in Ts...
, then this copy constructor shall be a trivial constexpr
constructor.constexpr variant(variant&& rhs) noexcept(see below);
rhs
has an active member of type T
, initializes the active member as if direct-non-list-initializing an object of type T
with the expression std::move(*rhs.target<T>())
; otherwise, no member is initialized. bool(rhs)
is unchanged.rhs.which() == this->which()
.T
.noexcept
is equivalent to the logical AND of std::is_nothrow_move_constructible_v<Ts>...
. This constructor shall not participate in overload resolution unless std::is_move_constructible_v<T>
is true
for all T
in Ts...
. If std::is_trivially_copyable_v<T>
is true
for all T
in Ts...
, then this move constructor shall be a trivial constexpr
constructor.template <class U>
constexpr variant(U&& v);
T
be one of the types in Ts...
for which std::forward<U>(u)
is unambiguously convertible to by overload resolution rules.T
with the expression std::forward<U>(v)
.*this
has an active member.T
.std::is_same_v<std::decay_t<U>, variant>
is false
, there is a type T
in Ts...
for which std::forward<U>(u)
is unambiguously convertible to by overload resolution rules, and std::is_constructible_v<T, U>
is true
. If T
's selected constructor is a constexpr
constructor, this constructor shall be a constexpr
constructor.template <class U>
constexpr explicit variant(U&& v);
T
be one of the types in Ts...
for which std::is_constructible_v<T, U>
is true
.T
with the expression std::forward<U>(v)
.*this
has an active member.T
.std::is_same_v<std::decay_t<U>, variant>
is false
, std::forward<U>(u)
is not convertible to any T
in Ts...
, and there is a single type T
in Ts...
for which std::is_constructible_v<T, U>
is true
. If T
's selected constructor is a constexpr
constructor, this constructor shall be a constexpr
constructor.template <std::size_t I, class ...Args>
constexpr explicit variant(in_place_index_t<I>, Args&&... args);
T
be the I
th element in Ts...
, where indexing is zero-based.T
with the arguments std::forward<Args>(args)...
.*this
has an active member of type T
.T
.I < sizeof...(Ts)
, and std::is_constructible_v<T, Args...>
is true
. If T
's selected constructor is a constexpr
constructor, this constructor shall be a constexpr
constructor.template <std::size_t I, class U, class ...Args>
constexpr explicit variant(in_place_index_t<I>, std::initializer_list<U> il, Args&&... args);
T
be the I
th element in Ts...
, where indexing is zero-based.T
with the arguments il, std::forward<Args>(args)...
.*this
has an active member of type T
.T
.I < sizeof...(Ts)
, and std::is_constructible_v<T, std::initializer_list<U>&, Args...>
is true
. If T
's selected constructor is a constexpr
constructor, this constructor shall be a constexpr
constructor.template <class T, class ...Args>
constexpr explicit variant(in_place_type_t<T>, Args&&... args);
variant(in_place<I>, std::forward<Args>(args)...)
where I
is the zero-based index of T
in Ts...
.T
in Ts...
, and std::is_constructible_v<T, Args...>
is true
. If T
's selected constructor is a constexpr
constructor, this constructor shall be a constexpr
constructor.template <class T, class U, class ...Args>
constexpr explicit variant(in_place_type_t<T>, std::initializer_list<U> il, Args&&... args);
variant(in_place<I>, il, std::forward<Args>(args)...)
where I
is the zero-based index of T
in Ts...
.T
in Ts...
, and std::is_constructible_v<T, std::initializer_list<U>&, Args...>
is true
. If T
's selected constructor is a constexpr
constructor, this constructor shall be a constexpr
constructor.~variant();
*this
has an active member of type T
, destroys the active member as if by calling target<T>()->~T()
.std::is_trivially_destructible_v<T>
is true
for all T
in Ts...
, then this destructor shall be trivial.constexpr variant& operator=(variant const& rhs);
*this
and rhs
have an active member of type T
, assigns to the active member the expression *rhs.target<T>()
;*this
has an active member of type U
, destroys the active member by calling target<U>()->~U()
. Then, if rhs
has an active member of type T
, initializes the active member as if direct-non-list-initializing an object of type T
with the expression *rhs.target<T>()
.*this
.rhs.which() == this->which()
.T
's copy assignment, the state of the active member is as defined by the exception safety guarantee of T
's copy assignment. If an exception is thrown during the call to T
's copy constructor, *this
has no active member, and the previous active member (if any) has been destroyed. This function shall be defined as deleted unless std::is_copy_assignable_v<T> && std::is_copy_constructible_v<T>
is true
for all T
in Ts...
. If std::is_trivially_copyable_v<T>
is true
for all T
in Ts...
, then this copy assignment operator shall be a trivial constexpr
assignment operator.constexpr variant& operator=(variant&& rhs) noexcept(see below);
*this
and rhs
have an active member of type T
, assigns to the active member the expression std::move(*rhs.target<T>())
;*this
has an active member of type U
, destroys the active member by calling target<U>()->~U()
. Then, if rhs
has an active member of type T
, initializes the active member as if direct-non-list-initializing an object of type T
with the expression std::move(*rhs.target<Tn>())
.bool(rhs)
is unchanged.*this
.rhs.which() == this->which()
.T
's move assignment, the state of both active members is determined by the exception safety guarantee of T
's move assignment. If an exception is thrown during the call to T
's move constructor, *this
has no active member, the previous active member (if any) has been destroyed, and the state of the active member of rhs
is determined by the exception safety guarantee of T
's move constructor. The expression inside noexcept
is equivalent to the logical AND of std::is_nothrow_move_assignable_v<Ts>...
and std::is_nothrow_move_constructible_v<Ts>...
. This function shall not participate in overload resolution unless std::is_move_assignable_v<T> && std::is_move_constructible_v<T>
is true
for all T
in Ts...
. If std::is_trivially_copyable_v<T>
is true
for all T
in Ts...
, then this move assignment operator shall be a trivial constexpr
assignment operator.template <class U>
constexpr variant& operator=(U&& v);
T
be one of the types in Ts...
for which std::forward<U>(u)
is unambiguously convertible to by overload resolution rules.*this
has an active member of type T
, assigns to the active member the expression std::forward<U>(v)
;*this = {}
. Then, initializes the active member as if direct-non-list-initializing an object of type T
with the expression std::forward<U>(v)
.*this
.*this
has an active member.T
's assignment, the state of the active member is as defined by the exception safety guarantee of T
's assignment. If an exception is thrown during the call to T
's constructor, *this
has no active member, and the previous active member (if any) has been destroyed. This function shall not participate in overload resolution unless std::is_same_v<std::decay_t<U>, variant>
is false
, there is a type T
in Ts...
for which std::forward<U>(u)
is unambiguously convertible to by overload resolution rules, and std::is_constructible_v<T, U>
is true
. This function shall be defined as deleted unless std::is_assignable_v<T&, U>
is true
. If std::is_trivially_copyable_v<T>
is true
for all T
in Ts...
and T
's selected constructor is a constexpr
constructor, then this function shall be a constexpr
function.template <std::size_t I, class ...Args>
constexpr T& emplace(Args&&... args);
T
be the I
th element in Ts...
, where indexing is zero-based.I < sizeof...(Ts)
.*this = {}
. Then, initializes the active member as if direct-non-list-initializing an object of type T
with the arguments std::forward<Args>(args)...
.*this
has an active member of type T
.T
.T
's constructor, *this
has no active member, and the previous active member (if any) has been destroyed. This function shall not participate in overload resolution unless std::is_constructible_v<T, Args...>
is true
. If std::is_trivially_copyable_v<T> && std::is_copy_assignable_v<T>
is true
for all T
in Ts...
and T
's selected constructor is a constexpr
constructor, then this function shall be a constexpr
function.template <std::size_t I, class U, class ...Args>
constexpr T& emplace(std::initializer_list<U> il, Args&&... args);
T
be the I
th element in Ts...
, where indexing is zero-based.I < sizeof...(Ts)
.*this = {}
. Then, initializes the active member as if direct-non-list-initializing an object of type T
with the arguments il, std::forward<Args>(args)...
.*this
has an active member of type T
.T
.T
's constructor, *this
has no active member, and the previous active member (if any) has been destroyed. This function shall not participate in overload resolution unless std::is_constructible_v<T, std::initializer_list<U>&, Args...>
is true
. If std::is_trivially_copyable_v<T> && std::is_copy_assignable_v<T>
is true
for all T
in Ts...
and T
's selected constructor is a constexpr
constructor, then this function shall be a constexpr
function.template <class T, class ...Args>
constexpr T& emplace(Args&&... args);
T
shall occur exactly once in Ts...
.emplace<I>(std::forward<Args>(args)...)
where I
is the zero-based index of T
in Ts...
.std::is_constructible_v<T, Args...>
is true
. If std::is_trivially_copyable_v<T> && std::is_copy_assignable_v<T>
is true
for all T
in Ts...
and T
's selected constructor is a constexpr
constructor, then this function shall be a constexpr
function.template <class T, class U, class ...Args>
constexpr T& emplace(std::initializer_list<U> il, Args&&... args);
T
shall occur exactly once in Ts...
.emplace<I>(il, std::forward<Args>(args)...)
where I
is the zero-based index of T
in Ts...
.std::is_constructible_v<T, std::initializer_list<U>&, Args...>
is true
. If std::is_trivially_copyable_v<T> && std::is_copy_assignable_v<T>
is true
for all T
in Ts...
and T
's selected constructor is a constexpr
constructor, then this function shall be a constexpr
function.constexpr void swap(variant& rhs) noexcept(see below);
T
shall be swappable and std::is_move_constructible_v<T>
is true
for all T
in Ts...
.*this
and rhs
have an active member of type T
, calls swap(*this->target<T>(), *rhs.target<T>())
;std::swap(*this, rhs)
.swap
the state of the active members of type T
is determined by the exception safety guarantee of swap
for lvalues of T
. If an exception is thrown during the call to a move constructor, the state of *this
and rhs
is unspecified. The expression inside noexcept
is equivalent to the logical AND of std::is_nothrow_move_constructible_v<T> && std::is_nothrow_swappable_v<T>
for all T
in Ts...
. If std::is_trivially_copyable_v<T> && std::is_copy_assignable_v<T>
is true
for all T
in Ts...
, then this function shall be a constexpr
function.constexpr explicit operator bool() const noexcept;
true
if and only if *this
has an active member.constexpr
function.constexpr std::size_t which() const noexcept;
*this
has one. Otherwise, returns npos
.constexpr
function.constexpr std::type_info const& target_type() const noexcept;
*this
has an active member of type T
, typeid(T)
; otherwise typeid(void)
.constexpr
function.constexpr void* target() noexcept;
*this
has an active member, a pointer to the active member; otherwise a null pointer.constexpr
function.constexpr void const* target() const noexcept;
*this
has an active member, a pointer to the active member; otherwise a null pointer.constexpr
function.template <class T>
constexpr T* target() noexcept;
*this
has an active member of type T
or of a type of which T
is an unambiguous and accessible base class, a pointer to the active member; otherwise a null pointer.constexpr
function.template <class T>
constexpr T const* target() const noexcept;
*this
has an active member of type T
or of a type of which T
is an unambiguous and accessible base class, a pointer to the active member; otherwise a null pointer.constexpr
function.template <std::size_t I> using in_place_index_t = void(*)(unspecified<I>); template <class T> using in_place_type_t = void(*)(unspecified<T>); template <std::size_t I> void in_place(unspecified<I>); template <class T> void in_place(unspecified<T>);
The template aliases in_place_index_t
and in_place_type_t
are used as unique types to disambiguate constructor and function overloading. Specifically, variant<Ts...>
has a constructor with in_place_type_t<T>
as the first parameter, followed by a parameter pack; this indicates that T
should be constructed in-place (as if by a call to a placement new expression) with the forwarded pack expansion as arguments for the initialization of T
.
bad_variant_access
class bad_variant_access : public std::exception { public: bad_variant_access() noexcept; char const* what() const noexcept override; };
Objects of type bad_variant_access
are thrown to report attempts to access an inactive member of a variant
object.
bad_variant_access() noexcept;
bad_variant_access
object.char const* what() const noexcept override;
template <class T>
struct variant_size;
variant_size<T>
shall meet the UnaryTypeTrait
requirements with a BaseCharacteristic
of std::integral_constant<std::size_t, N>
for some N
if T
is a variant-like type; otherwise it shall be empty.template <class ...Ts>
struct variant_size<variant<Ts...>>;
BaseCharacteristic
of std::integral_constant<std::size_t, sizeof...(Ts)>
.template <class T>
struct variant_size<T const>;
VS
denote variant_size<T>
of the cv-unqualified type T
. Has a BaseCharacteristic
of std::integral_constant<std::size_t, VS::value>
if T
is a variant-like type; otherwise it is empty.template <std::size_t I, class T>
struct variant_element;
variant_element<I, T>
shall meet the TransformationTrait
requirements with a member typedef type
that names the I
th member of T
, where indexing is zero-based.template <std::size_t I, class ...Ts>
struct variant_element<I, variant<Ts...>>;
I < sizeof...(Ts)
. Otherwise, the program is ill-formed.type
shall name the type of the I
th element of Ts...
, where indexing is zero-based.template <std::size_t I, class T>
struct variant_element<I, T const>;
VE
denote variant_element<I, T>
of the cv-unqualified type T
. The member typedef type
names std::add_const_t<typename VE::type>
.template <std::size_t I, class ...Ts>
constexpr variant_element_t<I, variant<Ts...>>& get(variant<Ts...>& v);
I < sizeof...(Ts)
. Otherwise, the program is ill-formed.I
th member of v
if it is active, where indexing is zero-based.bad_variant_access
if the I
th member of v
is not active.constexpr
function.template <std::size_t I, class ...Ts>
constexpr variant_element_t<I, variant<Ts...>> const& get(variant<Ts...> const& v);
I < sizeof...(Ts)
. Otherwise, the program is ill-formed.I
th member of v
if it is active, where indexing is zero-based.bad_variant_access
if the I
th member of v
is not active.constexpr
function.template <std::size_t I, class ...Ts>
constexpr variant_element_t<I, variant<Ts...>>&& get(variant<Ts...>&& v);
I < sizeof...(Ts)
. Otherwise, the program is ill-formed.std::forward<variant_element_t<I, variant<Ts...>>>(get<I>(v))
.constexpr
function.template <std::size_t I, class ...Ts>
constexpr variant_element_t<I, variant<Ts...>> const&& get(variant<Ts...> const&& v);
I < sizeof...(Ts)
. Otherwise, the program is ill-formed.std::forward<variant_element_t<I, variant<Ts...>> const>(get<I>(v))
.constexpr
function.template <class T, class ...Ts>
constexpr T& get(variant<Ts...>& v);
T
occurs exactly once in Ts...
. Otherwise, the program is ill-formed.v
if it is of type T
.bad_variant_access
if the active member of v
is not of type T
.constexpr
function.template <class T, class ...Ts>
constexpr T const& get(variant<Ts...> const& v);
T
occurs exactly once in Ts...
. Otherwise, the program is ill-formed.v
if it is of type T
.bad_variant_access
if the active member of v
is not of type T
.constexpr
function.template <class T, class ...Ts>
constexpr T&& get(variant<Ts...>&& v);
T
occurs exactly once in Ts...
. Otherwise, the program is ill-formed.std::forward<T>(get<T>(v))
.constexpr
function.template <class T, class ...Ts>
constexpr T const&& get(variant<Ts...> const&& v);
T
occurs exactly once in Ts...
. Otherwise, the program is ill-formed.std::forward<T const>(get<T>(v))
.constexpr
function.template <std::size_t I, class ...Ts>
constexpr variant_element_t<I, variant<Ts...>>* get_if(variant<Ts...>* v) noexcept;
I < sizeof...(Ts)
. Otherwise, the program is ill-formed.v != nullptr
, a pointer to the I
th member of *v
if it is active, where indexing is zero-based; otherwise, nullptr
.constexpr
function.template <std::size_t I, class ...Ts>
constexpr variant_element_t<I, variant<Ts...>> const* get_if(variant<Ts...> const* v) noexcept;
I < sizeof...(Ts)
. Otherwise, the program is ill-formed.v != nullptr
, a const pointer to the I
th member of *v
if it is active, where indexing is zero-based; otherwise, nullptr
.constexpr
function.template <class T, class ...Ts>
constexpr T* get_if(variant<Ts...>* v) noexcept;
T
occurs exactly once in Ts...
. Otherwise, the program is ill-formed.v != nullptr
, a pointer to the active member of *v
if it is of type T
; otherwise, nullptr
.constexpr
function.template <class T, class ...Ts>
constexpr T const* get_if(variant<Ts...> const* v) noexcept;
T
occurs exactly once in Ts...
. Otherwise, the program is ill-formed.v != nullptr
, a const pointer to the active member of *v
if it is of type T
; otherwise, nullptr
.constexpr
function.template <class ...Ts>
constexpr bool operator==(variant<Ts...> const& lhs, variant<Ts...> const& rhs);
*lhs.target<T>() == *rhs.target<T>()
shall be convertible to bool
for all T
in Ts...
.lhs.which() != rhs.which()
, false
; otherwise, if !bool(lhs)
, true
; otherwise, *lhs.target<T>() == *rhs.target<T>()
where T
is the type of the active member of both lhs
and rhs
.*lhs.target<T>() == *rhs.target<T>()
is well-formed for all T
in Ts...
. This function shall be a constexpr
function unless lhs.which() == rhs.which()
and *lhs.target<T>() == *rhs.target<T>()
where T
is the type of the active member of both lhs
and rhs
is not a constant expression.template <class ...Ts>
constexpr bool operator!=(variant<Ts...> const& lhs, variant<Ts...> const& rhs);
*lhs.target<T>() != *rhs.target<T>()
shall be convertible to bool
for all T
in Ts...
.lhs.which() != rhs.which()
, true
; otherwise, if !bool(lhs)
, false
; otherwise, *lhs.target<T>() != *rhs.target<T>()
where T
is the type of the active member of both lhs
and rhs
.*lhs.target<T>() != *rhs.target<T>()
is well-formed for all T
in Ts...
. This function shall be a constexpr
function unless lhs.which() == rhs.which()
and *lhs.target<T>() != *rhs.target<T>()
where T
is the type of the active member of both lhs
and rhs
is not a constant expression.template <class ...Ts>
constexpr bool operator<(variant<Ts...> const& lhs, variant<Ts...> const& rhs);
*lhs.target<T>() < *rhs.target<T>()
shall be convertible to bool
for all T
in Ts...
.!bool(rhs)
, false
; otherwise, if !bool(lhs)
, true
; otherwise, if lhs.which() == rhs.which()
, *lhs.target<T>() < *rhs.target<T>()
where T
is the type of the active member of both lhs
and rhs
; otherwise, lhs.which() < rhs.which()
.*lhs.target<T>() < *rhs.target<T>()
is well-formed for all T
in Ts...
. This function shall be a constexpr
function unless lhs.which() == rhs.which()
and *lhs.target<T>() < *rhs.target<T>()
where T
is the type of the active member of both lhs
and rhs
is not a constant expression.template <class ...Ts>
constexpr bool operator>(variant<Ts...> const& lhs, variant<Ts...> const& rhs);
*lhs.target<T>() > *rhs.target<T>()
shall be convertible to bool
for all T
in Ts...
.!bool(lhs)
, false
; otherwise, if !bool(rhs)
, true
; otherwise, if lhs.which() == rhs.which()
, *lhs.target<T>() > *rhs.target<T>()
where T
is the type of the active member of both lhs
and rhs
; otherwise, lhs.which() > rhs.which()
.*lhs.target<T>() > *rhs.target<T>()
is well-formed for all T
in Ts...
. This function shall be a constexpr
function unless lhs.which() == rhs.which()
and *lhs.target<T>() > *rhs.target<T>()
where T
is the type of the active member of both lhs
and rhs
is not a constant expression.template <class ...Ts>
constexpr bool operator<=(variant<Ts...> const& lhs, variant<Ts...> const& rhs);
*lhs.target<T>() <= *rhs.target<T>()
shall be convertible to bool
for all T
in Ts...
.!bool(lhs)
, true
; otherwise, if !bool(rhs)
, false
; otherwise, if lhs.which() == rhs.which()
, *lhs.target<T>() <= *rhs.target<T>()
where T
is the type of the active member of both lhs
and rhs
; otherwise, lhs.which() < rhs.which()
.*lhs.target<T>() <= *rhs.target<T>()
is well-formed for all T
in Ts...
. This function shall be a constexpr
function unless lhs.which() == rhs.which()
and *lhs.target<T>() <= *rhs.target<T>()
where T
is the type of the active member of both lhs
and rhs
is not a constant expression.template <class ...Ts>
constexpr bool operator>=(variant<Ts...> const& lhs, variant<Ts...> const& rhs);
*lhs.target<T>() >= *rhs.target<T>()
shall be convertible to bool
for all T
in Ts...
.!bool(rhs)
, true
; otherwise, if !bool(lhs)
, false
; otherwise, if lhs.which() == rhs.which()
, *lhs.target<T>() >= *rhs.target<T>()
where T
is the type of the active member of both lhs
and rhs
; otherwise, lhs.which() > rhs.which()
.*lhs.target<T>() >= *rhs.target<T>()
is well-formed for all T
in Ts...
. This function shall be a constexpr
function unless lhs.which() == rhs.which()
and *lhs.target<T>() >= *rhs.target<T>()
where T
is the type of the active member of both lhs
and rhs
is not a constant expression.Ts
template <class ...Ts, class U>
constexpr bool operator==(variant<Ts...> const& lhs, U const& rhs);
T
be one of the types in Ts...
for which rhs
is unambiguously convertible to by overload resolution rules.*lhs.target<T>() == rhs
shall be convertible to bool
.lhs
has an active member of type T
, *lhs.target<T>() == rhs
; otherwise, false
.T
in Ts...
for which rhs
is unambiguously convertible to by overload resolution rules, and the expression *lhs.target<T>() == rhs
is well-formed. This function shall be a constexpr
function unless lhs
has an active member of type T
and *lhs.target<T>() == rhs
is not a constant expression.template <class U, class ...Ts>
constexpr bool operator==(U const& lhs, variant<Ts...> const& rhs);
T
be one of the types in Ts...
for which lhs
is unambiguously convertible to by overload resolution rules.lhs == *rhs.target<T>()
shall be convertible to bool
.rhs
has an active member of type T
, lhs == *rhs.target<T>()
; otherwise, false
.T
in Ts...
for which lhs
is unambiguously convertible to by overload resolution rules, and the expression lhs == *rhs.target<T>()
is well-formed. This function shall be a constexpr
function unless rhs
has an active member of type T
and lhs == *rhs.target<T>()
is not a constant expression.template <class ...Ts, class U>
constexpr bool operator!=(variant<Ts...> const& lhs, U const& rhs);
T
be one of the types in Ts...
for which rhs
is unambiguously convertible to by overload resolution rules.*lhs.target<T>() != rhs
shall be convertible to bool
.lhs
has an active member of type T
, *lhs.target<T>() != rhs
; otherwise, true
.T
in Ts...
for which rhs
is unambiguously convertible to by overload resolution rules, and the expression *lhs.target<T>() != rhs
is well-formed. This function shall be a constexpr
function unless lhs
has an active member of type T
and *lhs.target<T>() != rhs
is not a constant expression.template <class U, class ...Ts>
constexpr bool operator!=(U const& lhs, variant<Ts...> const& rhs);
T
be one of the types in Ts...
for which lhs
is unambiguously convertible to by overload resolution rules.lhs != *rhs.target<T>()
shall be convertible to bool
.rhs
has an active member of type T
, lhs != *rhs.target<T>()
; otherwise, true
.T
in Ts...
for which lhs
is unambiguously convertible to by overload resolution rules, and the expression lhs != *rhs.target<T>()
is well-formed. This function shall be a constexpr
function unless rhs
has an active member of type T
and lhs != *rhs.target<T>()
is not a constant expression.template <class ...Ts, class U>
constexpr bool operator<(variant<Ts...> const& lhs, U const& rhs);
T
be one of the types in Ts...
for which rhs
is unambiguously convertible to by overload resolution rules.*lhs.target<T>() < rhs
shall be convertible to bool
.!bool(lhs)
, true
; otherwise, if lhs
has an active member of type T
, *lhs.target<T>() < rhs
; otherwise, lhs.which() < I
where I
is the zero-based index of T
in Ts...
.T
in Ts...
for which rhs
is unambiguously convertible to by overload resolution rules, and the expression *lhs.target<T>() < rhs
is well-formed. This function shall be a constexpr
function unless lhs
has an active member of type T
and *lhs.target<T>() < rhs
is not a constant expression.template <class U, class ...Ts>
constexpr bool operator<(U const& lhs, variant<Ts...> const& rhs);
T
be one of the types in Ts...
for which lhs
is unambiguously convertible to by overload resolution rules.lhs < *rhs.target<T>()
shall be convertible to bool
.!bool(rhs)
, false
; otherwise, if rhs
has an active member of type T
, lhs < *rhs.target<T>()
; otherwise, I < rhs.which()
where I
is the zero-based index of T
in Ts...
.T
in Ts...
for which lhs
is unambiguously convertible to by overload resolution rules, and the expression lhs < *rhs.target<T>()
is well-formed. This function shall be a constexpr
function unless rhs
has an active member of type T
and lhs < *rhs.target<T>()
is not a constant expression.template <class ...Ts, class U>
constexpr bool operator>(variant<Ts...> const& lhs, U const& rhs);
T
be one of the types in Ts...
for which rhs
is unambiguously convertible to by overload resolution rules.*lhs.target<T>() > rhs
shall be convertible to bool
.!bool(lhs)
, false
; otherwise, if lhs
has an active member of type T
, *lhs.target<T>() > rhs
; otherwise, lhs.which() > I
where I
is the zero-based index of T
in Ts...
.T
in Ts...
for which rhs
is unambiguously convertible to by overload resolution rules, and the expression *lhs.target<T>() > rhs
is well-formed. This function shall be a constexpr
function unless lhs
has an active member of type T
and *lhs.target<T>() > rhs
is not a constant expression.template <class U, class ...Ts>
constexpr bool operator>(U const& lhs, variant<Ts...> const& rhs);
T
be one of the types in Ts...
for which lhs
is unambiguously convertible to by overload resolution rules.lhs > *rhs.target<T>()
shall be convertible to bool
.!bool(rhs)
, true
; otherwise, if rhs
has an active member of type T
, lhs > *rhs.target<T>()
; otherwise, I > rhs.which()
where I
is the zero-based index of T
in Ts...
.T
in Ts...
for which lhs
is unambiguously convertible to by overload resolution rules, and the expression lhs > *rhs.target<T>()
is well-formed. This function shall be a constexpr
function unless rhs
has an active member of type T
and lhs > *rhs.target<T>()
is not a constant expression.template <class ...Ts, class U>
constexpr bool operator<=(variant<Ts...> const& lhs, U const& rhs);
T
be one of the types in Ts...
for which rhs
is unambiguously convertible to by overload resolution rules.*lhs.target<T>() <= rhs
shall be convertible to bool
.!bool(lhs)
, true
; otherwise, if lhs
has an active member of type T
, *lhs.target<T>() <= rhs
; otherwise, lhs.which() < I
where I
is the zero-based index of T
in Ts...
.T
in Ts...
for which rhs
is unambiguously convertible to by overload resolution rules, and the expression *lhs.target<T>() <= rhs
is well-formed. This function shall be a constexpr
function unless lhs
has an active member of type T
and *lhs.target<T>() <= rhs
is not a constant expression.template <class U, class ...Ts>
constexpr bool operator<=(U const& lhs, variant<Ts...> const& rhs);
T
be one of the types in Ts...
for which lhs
is unambiguously convertible to by overload resolution rules.lhs <= *rhs.target<T>()
shall be convertible to bool
.!bool(rhs)
, false
; otherwise, if rhs
has an active member of type T
, lhs <= *rhs.target<T>()
; otherwise, I < rhs.which()
where I
is the zero-based index of T
in Ts...
.T
in Ts...
for which lhs
is unambiguously convertible to by overload resolution rules, and the expression lhs <= *rhs.target<T>()
is well-formed. This function shall be a constexpr
function unless rhs
has an active member of type T
and lhs <= *rhs.target<T>()
is not a constant expression.template <class ...Ts, class U>
constexpr bool operator>=(variant<Ts...> const& lhs, U const& rhs);
T
be one of the types in Ts...
for which rhs
is unambiguously convertible to by overload resolution rules.*lhs.target<T>() >= rhs
shall be convertible to bool
.!bool(lhs)
, false
; otherwise, if lhs
has an active member of type T
, *lhs.target<T>() >= rhs
; otherwise, lhs.which() > I
where I
is the zero-based index of T
in Ts...
.T
in Ts...
for which rhs
is unambiguously convertible to by overload resolution rules, and the expression *lhs.target<T>() >= rhs
is well-formed. This function shall be a constexpr
function unless lhs
has an active member of type T
and *lhs.target<T>() >= rhs
is not a constant expression.template <class U, class ...Ts>
constexpr bool operator>=(U const& lhs, variant<Ts...> const& rhs);
T
be one of the types in Ts...
for which lhs
is unambiguously convertible to by overload resolution rules.lhs >= *rhs.target<T>()
shall be convertible to bool
.!bool(rhs)
, true
; otherwise, if rhs
has an active member of type T
, lhs >= *rhs.target<T>()
; otherwise, I > rhs.which()
where I
is the zero-based index of T
in Ts...
.T
in Ts...
for which lhs
is unambiguously convertible to by overload resolution rules, and the expression lhs >= *rhs.target<T>()
is well-formed. This function shall be a constexpr
function unless rhs
has an active member of type T
and lhs >= *rhs.target<T>()
is not a constant expression.template <class R, class F, class ...Vs>
constexpr R apply(F&& f, Vs&&... vs);
Vi
be the i
-th type in Vs...
, where all indexing is zero-based.i
, Vi
shall be either a specialization of variant
or publicly and unambiguously derived, directly or indirectly, from one. Let Ui
be the i
-th variant
specialization. INVOKE(std::forward<F>(f), get<Is>(std::forward<Vs>(vs))..., R)
shall be a valid expression for all Is...
in the range [0u, variant_size_v<Ui>)...
.INVOKE(std::forward<F>(f), get<Is>(std::forward<Vs>(vs))...), R)
where Is...
are the zero-based indices of the active members of vs...
.bad_variant_access
if any of vs...
has no active member.constexpr
function.template <class F, class ...Vs>
constexpr R apply(F&& f, Vs&&... vs);
Ri...
be the return types of every potentially evaluated INVOKE
expression; if every Ri...
is the same type, then let R
be that type.
apply<R>(std::forward<F>(f), std::forward<Vs>(vs)...)
.INVOKE
expression is the same type. If the selected function is a constant expression, then this function shall be a constexpr
function.template <class ...Ts>
constexpr void swap(variant<Ts...>& x, variant<Ts...>& y) noexcept(noexcept(x.swap(y)));
x.swap(y)
.std::is_move_constructible_v<T> && std::is_swappable_v<T>
is true
for all T
in Ts...
. If std::is_trivially_copyable_v<T> && std::is_copy_assignable_v<T>
is true
for all T
in Ts...
, then this function shall be a constexpr
function.template <class ...Ts>
struct std::hash<eggs::variants::variant<Ts...>>;
std::hash<variant<Ts...>>
is enabled if and only if every specialization in std::hash<std::remove_const_t<Ts>>...
is enabled. When enabled, for an object v
of type variant<Ts...>
, if v
has an active member of type T
, std::hash<variant<Ts...>>()(v)
shall evaluate to the same value as std::hash<T>()(*v.target<T>())
; otherwise it evaluates to an unspecified value. The member functions are guaranteed to be noexcept
if the member functions of every specialization in std::hash<std::remove_const_t<Ts>>...
are noexcept
.
Copyright Agustín Bergé, Fusion Fenix 2014-2017
Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)