STL/stl/inc/variant

1722 строки
82 KiB
C++

// variant standard header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef _VARIANT_
#define _VARIANT_
#include <yvals.h>
#if _STL_COMPILER_PREPROCESSOR
#if !_HAS_CXX17
_EMIT_STL_WARNING(STL4038, "The contents of <variant> are available only with C++17 or later.");
#else // ^^^ !_HAS_CXX17 / _HAS_CXX17 vvv
#if _HAS_CXX20
#include <compare>
#endif // _HAS_CXX20
#include <exception>
#include <initializer_list>
#include <type_traits>
#include <utility>
#include <xsmf_control.h>
#include <xutility>
#pragma pack(push, _CRT_PACKING)
#pragma warning(push, _STL_WARNING_LEVEL)
#pragma warning(disable : _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new
_STD_BEGIN
template <class...>
struct _Meta_list; // a sequence of types (not defined)
template <class _List>
struct _Meta_front_;
template <class _List>
using _Meta_front =
// extract the first type in a sequence (head of list)
typename _Meta_front_<_List>::type;
template <template <class...> class _List, class _First, class... _Rest>
struct _Meta_front_<_List<_First, _Rest...>> {
using type = _First;
};
template <class _List>
struct _Meta_pop_front_;
template <class _List>
using _Meta_pop_front =
// subsequence including all but the first type (tail of list)
typename _Meta_pop_front_<_List>::type;
template <template <class...> class _List, class _First, class... _Rest>
struct _Meta_pop_front_<_List<_First, _Rest...>> {
using type = _List<_Rest...>;
};
template <class _List, class _Ty>
struct _Meta_push_front_;
template <class _List, class _Ty>
using _Meta_push_front =
// prepend a new type onto a sequence
typename _Meta_push_front_<_List, _Ty>::type;
template <template <class...> class _List, class... _Types, class _Ty>
struct _Meta_push_front_<_List<_Types...>, _Ty> {
using type = _List<_Ty, _Types...>;
};
template <class _Void, template <class...> class _Fn, class... _Args>
struct _Meta_quote_helper_;
template <template <class...> class _Fn, class... _Args>
struct _Meta_quote_helper_<void_t<_Fn<_Args...>>, _Fn, _Args...> {
using type = _Fn<_Args...>;
};
template <template <class...> class _Fn>
struct _Meta_quote { // encapsulate a template into a meta-callable type
template <class... _Types>
using _Invoke = typename _Meta_quote_helper_<void, _Fn, _Types...>::type;
};
template <class _Fn, class... _Args>
using _Meta_invoke = // invoke meta-callable _Fn with _Args
typename _Fn::template _Invoke<_Args...>;
template <class _Fn, class... _Args>
struct _Meta_bind_back { // construct a meta-callable that passes its arguments and _Args to _Fn
template <class... _Types>
using _Invoke = _Meta_invoke<_Fn, _Types..., _Args...>;
};
template <class _Fn, class _List>
struct _Meta_apply_;
template <class _Fn, class _List>
using _Meta_apply =
// unpack _List into the parameters of meta-callable _Fn
typename _Meta_apply_<_Fn, _List>::type;
template <class _Fn, template <class...> class _List, class... _Types>
struct _Meta_apply_<_Fn, _List<_Types...>> {
// invoke meta-callable _Fn with the parameters of a template specialization
using type = _Meta_invoke<_Fn, _Types...>;
};
template <class _Fn, class _Ty, _Ty... _Idxs>
struct _Meta_apply_<_Fn, integer_sequence<_Ty, _Idxs...>> {
// invoke meta-callable _Fn with the elements of an integer_sequence
using type = _Meta_invoke<_Fn, integral_constant<_Ty, _Idxs>...>;
};
template <class _Fn, class _List>
struct _Meta_transform_;
template <class _Fn, class _List>
using _Meta_transform =
// transform sequence of _Types... into sequence of _Fn<_Types...>
typename _Meta_transform_<_Fn, _List>::type;
template <template <class...> class _List, class _Fn, class... _Types>
struct _Meta_transform_<_Fn, _List<_Types...>> {
using type = _List<_Meta_invoke<_Fn, _Types>...>;
};
template <class, class, template <class...> class>
struct _Meta_repeat_n_c_;
template <size_t _Count, class _Ty, template <class...> class _Continue>
using _Meta_repeat_n_c =
// construct a sequence consisting of repetitions of _Ty
typename _Meta_repeat_n_c_<_Ty, make_index_sequence<_Count>, _Continue>::type;
template <class _Ty, size_t>
using _Meta_repeat_first_helper = _Ty;
template <class _Ty, size_t... _Idxs, template <class...> class _Continue>
struct _Meta_repeat_n_c_<_Ty, index_sequence<_Idxs...>, _Continue> {
using type = _Continue<_Meta_repeat_first_helper<_Ty, _Idxs>...>;
};
template <class _List, size_t _Idx, class = void>
struct _Meta_at_;
template <class _List, size_t _Idx>
using _Meta_at_c =
// Extract the _Idx-th type from _List
typename _Meta_at_<_List, _Idx>::type;
#ifdef __clang__
template <template <class...> class _List, class... _Types, size_t _Idx>
struct _Meta_at_<_List<_Types...>, _Idx, void_t<__type_pack_element<_Idx, _Types...>>> {
using type = __type_pack_element<_Idx, _Types...>;
};
#else // ^^^ defined(__clang__) / !defined(__clang__) vvv
template <class... _VoidPtrs>
struct _Meta_at_impl {
template <class _Ty, class... _Types>
static _Ty _Eval(_VoidPtrs..., _Ty*, _Types*...); // undefined
};
template <class _Ty>
constexpr _Identity<_Ty>* _Type_as_pointer() {
return nullptr;
}
template <template <class...> class _List, class... _Types, size_t _Idx>
struct _Meta_at_<_List<_Types...>, _Idx, enable_if_t<(_Idx < sizeof...(_Types))>> {
using type =
typename decltype(_Meta_repeat_n_c<_Idx, void*, _Meta_at_impl>::_Eval(_Type_as_pointer<_Types>()...))::type;
};
#endif // ^^^ !defined(__clang__) ^^^
template <class>
struct _Meta_as_list_;
template <class _Ty>
using _Meta_as_list =
// convert _Ty to a _Meta_list
typename _Meta_as_list_<_Ty>::type;
template <template <class...> class _List, class... _Types>
struct _Meta_as_list_<_List<_Types...>> {
// convert the parameters of an arbitrary template specialization to a _Meta_list of types
using type = _Meta_list<_Types...>;
};
template <class _Ty, _Ty... _Idxs>
struct _Meta_as_list_<integer_sequence<_Ty, _Idxs...>> {
// convert an integer_sequence to a _Meta_list of integral_constants
using type = _Meta_list<integral_constant<_Ty, _Idxs>...>;
};
template <class _List>
struct _Meta_as_integer_sequence_;
template <class _List>
using _Meta_as_integer_sequence =
// convert a list of integral_constants to an integer_sequence
typename _Meta_as_integer_sequence_<_List>::type;
template <template <class...> class _List, class _Ty, _Ty... _Idxs>
struct _Meta_as_integer_sequence_<_List<integral_constant<_Ty, _Idxs>...>> {
using type = integer_sequence<_Ty, _Idxs...>;
};
template <class...>
struct _Meta_concat_;
template <class... _Types>
using _Meta_concat =
// merge several lists into one
typename _Meta_concat_<_Types...>::type;
template <template <class...> class _List>
struct _Meta_concat_<_List<>> {
using type = _List<>;
};
template <template <class...> class _List, class... _Items1>
struct _Meta_concat_<_List<_Items1...>> {
using type = _List<_Items1...>;
};
template <template <class...> class _List, class... _Items1, class... _Items2>
struct _Meta_concat_<_List<_Items1...>, _List<_Items2...>> {
using type = _List<_Items1..., _Items2...>;
};
template <template <class...> class _List, class... _Items1, class... _Items2, class... _Items3>
struct _Meta_concat_<_List<_Items1...>, _List<_Items2...>, _List<_Items3...>> {
using type = _List<_Items1..., _Items2..., _Items3...>;
};
template <template <class...> class _List, class... _Items1, class... _Items2, class... _Items3, class... _Rest>
struct _Meta_concat_<_List<_Items1...>, _List<_Items2...>, _List<_Items3...>, _Rest...> {
using type = _Meta_concat<_List<_Items1..., _Items2..., _Items3...>, _Rest...>;
};
template <class _ListOfLists>
using _Meta_join =
// transform a list of lists of elements into a single list containing those elements
_Meta_apply<_Meta_quote<_Meta_concat>, _ListOfLists>;
template <class>
struct _Meta_cartesian_product_;
template <class _ListOfLists>
using _Meta_cartesian_product =
// find the n-ary Cartesian Product of the lists in the input list
typename _Meta_cartesian_product_<_ListOfLists>::type;
template <template <class...> class _List>
struct _Meta_cartesian_product_<_List<>> {
using type = _List<>;
};
template <template <class...> class _List1, template <class...> class _List2, class... _Items>
struct _Meta_cartesian_product_<_List1<_List2<_Items...>>> {
using type = _List1<_List2<_Items>...>;
};
template <template <class...> class _List1, class... _Items, template <class...> class _List2, class... _Lists>
struct _Meta_cartesian_product_<_List1<_List2<_Items...>, _Lists...>> {
using type = _Meta_join<_List1<_Meta_transform<_Meta_bind_back<_Meta_quote<_Meta_push_front>, _Items>,
_Meta_cartesian_product<_List1<_Lists...>>>...>>;
};
#define _STL_STAMP4(n, x) \
x(n); \
x(n + 1); \
x(n + 2); \
x(n + 3)
#define _STL_STAMP16(n, x) \
_STL_STAMP4(n, x); \
_STL_STAMP4(n + 4, x); \
_STL_STAMP4(n + 8, x); \
_STL_STAMP4(n + 12, x)
#define _STL_STAMP64(n, x) \
_STL_STAMP16(n, x); \
_STL_STAMP16(n + 16, x); \
_STL_STAMP16(n + 32, x); \
_STL_STAMP16(n + 48, x)
#define _STL_STAMP256(n, x) \
_STL_STAMP64(n, x); \
_STL_STAMP64(n + 64, x); \
_STL_STAMP64(n + 128, x); \
_STL_STAMP64(n + 192, x)
#define _STL_STAMP(n, x) x(_STL_STAMP##n, n)
_EXPORT_STD template <class... _Types>
class variant;
_EXPORT_STD template <class _Ty>
struct variant_size; // undefined
template <class _Ty>
struct variant_size<const _Ty> : variant_size<_Ty>::type {};
template <class _Ty>
struct _CXX20_DEPRECATE_VOLATILE variant_size<volatile _Ty> : variant_size<_Ty>::type {};
template <class _Ty>
struct _CXX20_DEPRECATE_VOLATILE variant_size<const volatile _Ty> : variant_size<_Ty>::type {};
_EXPORT_STD template <class _Ty>
constexpr size_t variant_size_v = variant_size<_Ty>::value;
template <class... _Types>
struct variant_size<variant<_Types...>> : integral_constant<size_t, sizeof...(_Types)> {};
_EXPORT_STD template <size_t _Idx, class _Ty>
struct variant_alternative; // undefined
_EXPORT_STD template <size_t _Idx, class _Ty>
using variant_alternative_t = typename variant_alternative<_Idx, _Ty>::type;
template <size_t _Idx, class _Ty>
struct variant_alternative<_Idx, const _Ty> {
using type = add_const_t<variant_alternative_t<_Idx, _Ty>>;
};
template <size_t _Idx, class _Ty>
struct _CXX20_DEPRECATE_VOLATILE variant_alternative<_Idx, volatile _Ty> {
using type = add_volatile_t<variant_alternative_t<_Idx, _Ty>>;
};
template <size_t _Idx, class _Ty>
struct _CXX20_DEPRECATE_VOLATILE variant_alternative<_Idx, const volatile _Ty> {
using type = add_cv_t<variant_alternative_t<_Idx, _Ty>>;
};
template <size_t _Idx, class... _Types>
struct variant_alternative<_Idx, variant<_Types...>> {
static_assert(_Idx < sizeof...(_Types), "variant index out of bounds");
#ifdef __clang__
using type = __type_pack_element<_Idx, _Types...>;
#else // ^^^ defined(__clang__) / !defined(__clang__) vvv
using type = _Meta_at_c<variant<_Types...>, _Idx>;
#endif // ^^^ !defined(__clang__) ^^^
};
_EXPORT_STD inline constexpr size_t variant_npos = _Meta_npos;
template <bool _TrivialDestruction, class... _Types>
class _Variant_storage_ {}; // empty storage (empty "_Types" case)
template <class... _Types>
using _Variant_storage = _Variant_storage_<conjunction_v<is_trivially_destructible<_Types>...>, _Types...>;
template <class _First, class... _Rest>
class _Variant_storage_<true, _First, _Rest...> { // Storage for variant alternatives (trivially destructible case)
public:
static constexpr size_t _Size = 1 + sizeof...(_Rest);
union {
remove_cv_t<_First> _Head;
_Variant_storage<_Rest...> _Tail;
};
_CONSTEXPR20 _Variant_storage_() noexcept {} // no initialization (no active member)
template <class... _Types>
constexpr explicit _Variant_storage_(integral_constant<size_t, 0>, _Types&&... _Args)
noexcept(is_nothrow_constructible_v<_First, _Types...>)
: _Head(static_cast<_Types&&>(_Args)...) {} // initialize _Head with _Args...
template <size_t _Idx, class... _Types, enable_if_t<(_Idx > 0), int> = 0>
constexpr explicit _Variant_storage_(integral_constant<size_t, _Idx>, _Types&&... _Args)
noexcept(is_nothrow_constructible_v<_Variant_storage<_Rest...>, integral_constant<size_t, _Idx - 1>, _Types...>)
: _Tail(integral_constant<size_t, _Idx - 1>{}, static_cast<_Types&&>(_Args)...) {} // initialize _Tail (recurse)
_NODISCARD constexpr _First& _Get() & noexcept {
return _Head;
}
_NODISCARD constexpr const _First& _Get() const& noexcept {
return _Head;
}
_NODISCARD constexpr _First&& _Get() && noexcept {
return _STD move(_Head);
}
_NODISCARD constexpr const _First&& _Get() const&& noexcept {
return _STD move(_Head);
}
};
template <class _First, class... _Rest>
class _Variant_storage_<false, _First, _Rest...> { // Storage for variant alternatives (non-trivially destructible case)
public:
static constexpr size_t _Size = 1 + sizeof...(_Rest);
union {
remove_cv_t<_First> _Head;
_Variant_storage<_Rest...> _Tail;
};
_CONSTEXPR20 ~_Variant_storage_()
#ifndef __clang__ // TRANSITION, LLVM-59854
noexcept
#endif // ^^^ no workaround ^^^
{
// explicitly non-trivial destructor (which would otherwise be defined as deleted
// since the class has a variant member with a non-trivial destructor)
}
_CONSTEXPR20 _Variant_storage_() noexcept {} // no initialization (no active member)
template <class... _Types>
constexpr explicit _Variant_storage_(integral_constant<size_t, 0>, _Types&&... _Args)
noexcept(is_nothrow_constructible_v<_First, _Types...>)
: _Head(static_cast<_Types&&>(_Args)...) {} // initialize _Head with _Args...
template <size_t _Idx, class... _Types, enable_if_t<(_Idx > 0), int> = 0>
constexpr explicit _Variant_storage_(integral_constant<size_t, _Idx>, _Types&&... _Args)
noexcept(is_nothrow_constructible_v<_Variant_storage<_Rest...>, integral_constant<size_t, _Idx - 1>, _Types...>)
: _Tail(integral_constant<size_t, _Idx - 1>{}, static_cast<_Types&&>(_Args)...) {} // initialize _Tail (recurse)
_Variant_storage_(_Variant_storage_&&) = default;
_Variant_storage_(const _Variant_storage_&) = default;
_Variant_storage_& operator=(_Variant_storage_&&) = default;
_Variant_storage_& operator=(const _Variant_storage_&) = default;
_NODISCARD constexpr _First& _Get() & noexcept {
return _Head;
}
_NODISCARD constexpr const _First& _Get() const& noexcept {
return _Head;
}
_NODISCARD constexpr _First&& _Get() && noexcept {
return _STD move(_Head);
}
_NODISCARD constexpr const _First&& _Get() const&& noexcept {
return _STD move(_Head);
}
};
#ifdef __cplusplus_winrt // TRANSITION, VSO-586813
// C++/CX is unable to store hats in unions. We instead store them inside a
// wrapper to enable minimal hats-in-variants support.
template <class _Ty>
struct _Variant_item {
remove_cv_t<_Ty> _Item;
template <class... _Types>
constexpr _Variant_item(_Types&&... _Args) noexcept(is_nothrow_constructible_v<_Ty, _Types...>)
: _Item(static_cast<_Types&&>(_Args)...) {}
};
template <class _First, class... _Rest>
class _Variant_storage_<false, _First ^, _Rest...> { // Storage for variant alternatives (^ case)
public:
static constexpr size_t _Size = 1 + sizeof...(_Rest);
union {
_Variant_item<_First ^> _Head;
_Variant_storage<_Rest...> _Tail;
};
_CONSTEXPR20 ~_Variant_storage_() noexcept {
// explicitly non-trivial destructor (which would otherwise be defined as deleted
// since the class has a variant member with a non-trivial destructor)
}
_CONSTEXPR20 _Variant_storage_() noexcept {} // no initialization (no active member)
template <class... _Types>
constexpr explicit _Variant_storage_(integral_constant<size_t, 0>, _Types&&... _Args)
noexcept(is_nothrow_constructible_v<_First ^, _Types...>)
: _Head(static_cast<_Types&&>(_Args)...) {} // initialize _Head with _Args...
template <size_t _Idx, class... _Types, enable_if_t<(_Idx > 0), int> = 0>
constexpr explicit _Variant_storage_(integral_constant<size_t, _Idx>, _Types&&... _Args)
noexcept(is_nothrow_constructible_v<_Variant_storage<_Rest...>, integral_constant<size_t, _Idx - 1>, _Types...>)
: _Tail(integral_constant<size_t, _Idx - 1>{}, static_cast<_Types&&>(_Args)...) {} // initialize _Tail (recurse)
_Variant_storage_(_Variant_storage_&&) = default;
_Variant_storage_(const _Variant_storage_&) = default;
_Variant_storage_& operator=(_Variant_storage_&&) = default;
_Variant_storage_& operator=(const _Variant_storage_&) = default;
_NODISCARD constexpr _First ^ &_Get() & noexcept {
return _Head._Item;
}
_NODISCARD constexpr _First ^ const& _Get() const& noexcept {
return _Head._Item;
}
_NODISCARD constexpr _First ^ &&_Get() && noexcept {
return _STD move(_Head)._Item;
}
_NODISCARD constexpr _First ^ const&& _Get() const&& noexcept {
return _STD move(_Head)._Item;
}
};
#endif // ^^^ workaround ^^^
template <size_t _Idx, class _Storage>
_NODISCARD constexpr decltype(auto) _Variant_raw_get(_Storage&& _Obj) noexcept {
// access the _Idx-th element of a _Variant_storage
if constexpr (_Idx == 0) {
return static_cast<_Storage&&>(_Obj)._Get();
} else if constexpr (_Idx == 1) {
return static_cast<_Storage&&>(_Obj)._Tail._Get();
} else if constexpr (_Idx == 2) {
return static_cast<_Storage&&>(_Obj)._Tail._Tail._Get();
} else if constexpr (_Idx == 3) {
return static_cast<_Storage&&>(_Obj)._Tail._Tail._Tail._Get();
} else if constexpr (_Idx == 4) {
return static_cast<_Storage&&>(_Obj)._Tail._Tail._Tail._Tail._Get();
} else if constexpr (_Idx == 5) {
return static_cast<_Storage&&>(_Obj)._Tail._Tail._Tail._Tail._Tail._Get();
} else if constexpr (_Idx == 6) {
return static_cast<_Storage&&>(_Obj)._Tail._Tail._Tail._Tail._Tail._Tail._Get();
} else if constexpr (_Idx == 7) {
return static_cast<_Storage&&>(_Obj)._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Get();
} else if constexpr (_Idx < 16) {
return _STD _Variant_raw_get<_Idx - 8>(
static_cast<_Storage&&>(_Obj)._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail);
} else if constexpr (_Idx < 32) {
return _STD _Variant_raw_get<_Idx - 16>(
static_cast<_Storage&&>(_Obj)
._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail);
} else if constexpr (_Idx < 64) {
return _STD _Variant_raw_get<_Idx - 32>(
static_cast<_Storage&&>(_Obj)
._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail
._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail);
} else { // _Idx >= 64
return _STD _Variant_raw_get<_Idx - 64>(
static_cast<_Storage&&>(_Obj)
._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail
._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail
._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail
._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail);
}
}
template <class _Ty, size_t _Tag>
struct _Tagged { // aggregate a runtime value and a compile-time tag value
static constexpr size_t _Idx = _Tag;
_Ty _Val;
};
template <class _Storage, size_t _Idx>
using _Variant_tagged_ref_t = _Tagged<decltype(_STD _Variant_raw_get<_Idx>(_STD declval<_Storage>()))&&, _Idx>;
template <class _Fn, class _Storage>
using _Variant_raw_visit_t = decltype(_STD declval<_Fn>()(_STD declval<_Variant_tagged_ref_t<_Storage, 0>>()));
template <size_t _Idx, class _Fn, class _Storage>
_NODISCARD constexpr _Variant_raw_visit_t<_Fn, _Storage> _Variant_raw_visit_dispatch(_Fn&& _Func, _Storage&& _Var)
noexcept(is_nothrow_invocable_v<_Fn, _Variant_tagged_ref_t<_Storage, _Idx>>) {
// call _Func with the _Idx-th element in _Storage (tagged with _Idx)
return static_cast<_Fn&&>(_Func)(
_Variant_tagged_ref_t<_Storage, _Idx>{_STD _Variant_raw_get<_Idx>(static_cast<_Storage&&>(_Var))});
}
template <class _Fn, class _Storage>
_NODISCARD constexpr _Variant_raw_visit_t<_Fn, _Storage> _Variant_raw_visit_valueless(_Fn&& _Func, _Storage&& _Obj)
noexcept(is_nothrow_invocable_v<_Fn, _Tagged<_Storage&&, variant_npos>>) {
// call _Func with _Storage (tagged with variant_npos)
return static_cast<_Fn&&>(_Func)(_Tagged<_Storage&&, variant_npos>{static_cast<_Storage&&>(_Obj)});
}
template <class _Fn, class _Storage, class _Indices = make_index_sequence<remove_reference_t<_Storage>::_Size>>
constexpr bool _Variant_raw_visit_noexcept = false;
template <class _Fn, class _Storage, size_t... _Idxs>
constexpr bool _Variant_raw_visit_noexcept<_Fn, _Storage, index_sequence<_Idxs...>> =
conjunction_v<is_nothrow_invocable<_Fn, _Tagged<_Storage&&, variant_npos>>,
is_nothrow_invocable<_Fn, _Variant_tagged_ref_t<_Storage, _Idxs>>...>;
template <class _Fn, class _Storage,
class _Indices = make_index_sequence<remove_reference_t<_Storage>::_Size>>
struct _Variant_raw_dispatch_table1; // undefined
template <class _Fn, class _Storage, size_t... _Idxs>
struct _Variant_raw_dispatch_table1<_Fn, _Storage, index_sequence<_Idxs...>> {
// map from canonical index to visitation target
using _Dispatch_t = _Variant_raw_visit_t<_Fn, _Storage> (*)(_Fn&&, _Storage&&)
noexcept(_Variant_raw_visit_noexcept<_Fn, _Storage>);
static constexpr _Dispatch_t _Array[] = {
&_STD _Variant_raw_visit_valueless<_Fn, _Storage>, &_STD _Variant_raw_visit_dispatch<_Idxs, _Fn, _Storage>...};
};
template <int _Strategy>
struct _Variant_raw_visit1;
template <>
struct _Variant_raw_visit1<-1> { // Fallback case for variants too large for any of the following "switch" strategies
template <class _Fn, class _Storage>
_NODISCARD static constexpr _Variant_raw_visit_t<_Fn, _Storage> _Visit(size_t _Idx, _Fn&& _Func, _Storage&& _Obj)
noexcept(_Variant_raw_visit_noexcept<_Fn, _Storage>) {
// dispatch a visitor for a _Variant_storage with many states
constexpr size_t _Size = remove_reference_t<_Storage>::_Size;
static_assert(_Size > 256);
constexpr auto& _Array = _Variant_raw_dispatch_table1<_Fn, _Storage>::_Array;
return _Array[_Idx](static_cast<_Fn&&>(_Func), static_cast<_Storage&&>(_Obj));
}
};
#define _STL_CASE(n) \
case (n) + 1: \
if constexpr ((n) < _Size) { \
return static_cast<_Fn&&>(_Func)( \
_Variant_tagged_ref_t<_Storage, (n)>{_STD _Variant_raw_get<(n)>(static_cast<_Storage&&>(_Obj))}); \
} \
_STL_UNREACHABLE; \
[[fallthrough]]
#define _STL_VISIT_STAMP(stamper, n) \
constexpr size_t _Size = remove_reference_t<_Storage>::_Size; \
static_assert(((n) == 4 || _Size > (n) / 4) && _Size <= (n)); \
switch (_Idx) { \
case 0: \
return static_cast<_Fn&&>(_Func)(_Tagged<_Storage&&, variant_npos>{static_cast<_Storage&&>(_Obj)}); \
\
stamper(0, _STL_CASE); \
default: \
_STL_UNREACHABLE; \
}
template <>
struct _Variant_raw_visit1<1> {
template <class _Fn, class _Storage>
_NODISCARD static constexpr _Variant_raw_visit_t<_Fn, _Storage> _Visit(size_t _Idx, _Fn&& _Func, _Storage&& _Obj)
noexcept(_Variant_raw_visit_noexcept<_Fn, _Storage>) {
// dispatch a visitor for a _Variant_storage with at most 4^1 states
_STL_STAMP(4, _STL_VISIT_STAMP);
}
};
template <>
struct _Variant_raw_visit1<2> {
template <class _Fn, class _Storage>
_NODISCARD static constexpr _Variant_raw_visit_t<_Fn, _Storage> _Visit(size_t _Idx, _Fn&& _Func, _Storage&& _Obj)
noexcept(_Variant_raw_visit_noexcept<_Fn, _Storage>) {
// dispatch a visitor for a _Variant_storage with at most 4^2 states
_STL_STAMP(16, _STL_VISIT_STAMP);
}
};
template <>
struct _Variant_raw_visit1<3> {
template <class _Fn, class _Storage>
_NODISCARD static constexpr _Variant_raw_visit_t<_Fn, _Storage> _Visit(size_t _Idx, _Fn&& _Func, _Storage&& _Obj)
noexcept(_Variant_raw_visit_noexcept<_Fn, _Storage>) {
// dispatch a visitor for a _Variant_storage with at most 4^3 states
_STL_STAMP(64, _STL_VISIT_STAMP);
}
};
template <>
struct _Variant_raw_visit1<4> {
template <class _Fn, class _Storage>
_NODISCARD static constexpr _Variant_raw_visit_t<_Fn, _Storage> _Visit(size_t _Idx, _Fn&& _Func, _Storage&& _Obj)
noexcept(_Variant_raw_visit_noexcept<_Fn, _Storage>) {
// dispatch a visitor for a _Variant_storage with at most 4^4 states
_STL_STAMP(256, _STL_VISIT_STAMP);
}
};
#undef _STL_VISIT_STAMP
#undef _STL_CASE
template <class _Storage, class _Fn>
_NODISCARD constexpr _Variant_raw_visit_t<_Fn, _Storage> _Variant_raw_visit(size_t _Idx, _Storage&& _Obj, _Fn&& _Func)
noexcept(_Variant_raw_visit_noexcept<_Fn, _Storage>) {
// Call _Func with _Storage if _Idx is variant_npos, and otherwise the _Idx-th element in _Storage.
// pre: _Idx + 1 <= remove_reference_t<_Storage>::_Size
constexpr size_t _Size = remove_reference_t<_Storage>::_Size;
constexpr int _Strategy = _Size <= 4 ? 1 : _Size <= 16 ? 2 : _Size <= 64 ? 3 : _Size <= 256 ? 4 : -1;
++_Idx; // bias index by +1 to map {variant_npos} U [0, _Size) to the contiguous range [0, _Size]
return _Variant_raw_visit1<_Strategy>::_Visit(_Idx, static_cast<_Fn&&>(_Func), static_cast<_Storage&&>(_Obj));
}
template <class...>
class _Variant_base;
inline constexpr size_t _Schar_max_as_size = static_cast<unsigned char>(-1) / 2;
inline constexpr size_t _Short_max_as_size = static_cast<unsigned short>(-1) / 2;
template <size_t _Count>
using _Variant_index_t = // signed so that conversion of -1 to size_t can cheaply sign extend
conditional_t<(_Count < _Schar_max_as_size), signed char, conditional_t<(_Count < _Short_max_as_size), short, int>>;
template <class... _Types>
struct _Variant_construct_visitor { // visitor that constructs the same alternative in a target _Variant_base as is
// currently active in a source _Variant_base from the source's contained value
_Variant_base<_Types...>& _Self;
template <class _Ty, size_t _Idx>
_CONSTEXPR20 void operator()(_Tagged<_Ty, _Idx> _Source) const noexcept(
disjunction_v<bool_constant<_Idx == variant_npos>, is_nothrow_constructible<remove_reference_t<_Ty>, _Ty>>) {
// initialize _Idx-th item in _Self from _Source
_STL_INTERNAL_CHECK(_Self.valueless_by_exception());
if constexpr (_Idx != variant_npos) {
_STD _Construct_in_place(
_Self._Storage(), integral_constant<size_t, _Idx>{}, static_cast<_Ty&&>(_Source._Val));
_Self._Set_index(_Idx);
}
}
};
template <class _Target, class... _Types>
constexpr bool _Variant_should_directly_construct_v =
disjunction_v<is_nothrow_constructible<_Target, _Types...>, negation<is_nothrow_move_constructible<_Target>>>;
template <class... _Types>
struct _Variant_assign_visitor { // visitor that implements assignment for variants with non-trivial alternatives
_Variant_base<_Types...>& _Self;
template <class _Ty, size_t _Idx>
_CONSTEXPR20 void operator()(_Tagged<_Ty, _Idx> _Source) const
noexcept(disjunction_v<bool_constant<_Idx == variant_npos>,
conjunction<is_nothrow_assignable<_Remove_cvref_t<_Ty>&, _Ty>,
is_nothrow_constructible<_Remove_cvref_t<_Ty>, _Ty>>>) {
// assign the _Idx-th alternative of _Self from _Source
if constexpr (_Idx == variant_npos) { // assign from valueless _Source
_Self._Reset();
} else {
if (_Self._Which == _Idx) { // same alternative: assign directly
auto& _Target = _STD _Variant_raw_get<_Idx>(_Self._Storage());
_Target = static_cast<_Ty&&>(_Source._Val);
} else { // different alternative
if constexpr (is_lvalue_reference_v<_Ty>) { // RHS is an lvalue: copy
if constexpr (_Variant_should_directly_construct_v<_Remove_cvref_t<_Ty>, _Ty>) {
// copy is nothrow or move throws; construct in place
_Self._Reset();
_STD _Construct_in_place(_Self._Storage(), integral_constant<size_t, _Idx>{}, _Source._Val);
} else { // copy throws and move does not; move from a temporary copy
auto _Temp = _Source._Val;
_Self._Reset();
_STD _Construct_in_place(_Self._Storage(), integral_constant<size_t, _Idx>{}, _STD move(_Temp));
}
} else { // RHS is an rvalue: move
_Self._Reset();
_STD _Construct_in_place(
_Self._Storage(), integral_constant<size_t, _Idx>{}, static_cast<_Ty&&>(_Source._Val));
}
_Self._Set_index(_Idx);
}
}
}
};
template <class... _Types> // Associate an integral discriminator with a _Variant_storage
class _Variant_base : private _Variant_storage<_Types...> {
public:
using _Index_t = _Variant_index_t<sizeof...(_Types)>;
static constexpr auto _Invalid_index = static_cast<_Index_t>(-1);
_Index_t _Which;
using _Storage_t = _Variant_storage<_Types...>;
_NODISCARD constexpr _Storage_t& _Storage() & noexcept { // access this variant's storage
return *this;
}
_NODISCARD constexpr const _Storage_t& _Storage() const& noexcept { // access this variant's storage
return *this;
}
_NODISCARD constexpr _Storage_t&& _Storage() && noexcept { // access this variant's storage
return _STD move(*this);
}
_NODISCARD constexpr const _Storage_t&& _Storage() const&& noexcept { // access this variant's storage
return _STD move(*this);
}
// initialize to the value-less state
_CONSTEXPR20 _Variant_base() noexcept : _Storage_t{}, _Which{_Invalid_index} {}
template <size_t _Idx, class... _UTypes,
enable_if_t<is_constructible_v<_Meta_at_c<variant<_Types...>, _Idx>, _UTypes...>, int> = 0>
constexpr explicit _Variant_base(in_place_index_t<_Idx>, _UTypes&&... _Args)
noexcept(is_nothrow_constructible_v<_Meta_at_c<variant<_Types...>, _Idx>, _UTypes...>)
: _Storage_t(integral_constant<size_t, _Idx>{}, static_cast<_UTypes&&>(_Args)...),
_Which{static_cast<_Index_t>(_Idx)} { // initialize alternative _Idx from _Args...
}
_NODISCARD constexpr bool valueless_by_exception() const noexcept { // does this variant NOT hold a value?
return _Which < 0;
}
_NODISCARD constexpr size_t index() const noexcept {
// index of the contained alternative or variant_npos if valueless_by_exception
return static_cast<size_t>(_Which);
}
_CONSTEXPR20 void _Set_index(const size_t _Idx) noexcept {
// record _Idx as the active alternative
// pre: the active alternative of *this is _Idx
_Which = static_cast<_Index_t>(_Idx);
}
template <size_t _Idx>
_CONSTEXPR20 void _Destroy() noexcept {
// destroy the contained value
// pre: _Idx == index()
using _Indexed_value_type = remove_cv_t<_Meta_at_c<variant<_Types...>, _Idx>>;
if constexpr (_Idx != variant_npos && !is_trivially_destructible_v<_Indexed_value_type>) {
_STD _Variant_raw_get<_Idx>(_Storage()).~_Indexed_value_type();
}
}
_CONSTEXPR20 void _Destroy() noexcept { // destroy the contained value, if any
if constexpr (!conjunction_v<is_trivially_destructible<_Types>...>) {
_STD _Variant_raw_visit(index(), _Storage(), [](auto _Ref) noexcept {
if constexpr (decltype(_Ref)::_Idx != variant_npos) {
using _Indexed_value_type = _Remove_cvref_t<decltype(_Ref._Val)>;
_Ref._Val.~_Indexed_value_type();
}
});
}
}
_CONSTEXPR20 void _Reset() noexcept { // transition to the valueless_by_exception state
_Destroy();
_Set_index(variant_npos);
}
template <size_t _Idx>
_CONSTEXPR20 void _Reset() noexcept {
// transition to the valueless_by_exception state
// pre: _Idx == index()
if constexpr (_Idx != variant_npos) {
_Destroy<_Idx>();
_Set_index(variant_npos);
}
}
_CONSTEXPR20 void _Construct_from(const _Variant_base& _That)
noexcept(conjunction_v<is_nothrow_copy_constructible<_Types>...>) {
// copy _That's contained value into *this
// pre: valueless_by_exception()
_STD _Variant_raw_visit(_That.index(), _That._Storage(), _Variant_construct_visitor<_Types...>{*this});
}
_CONSTEXPR20 void _Construct_from(_Variant_base&& _That)
noexcept(conjunction_v<is_nothrow_move_constructible<_Types>...>) {
// move _That's contained value into *this
// pre: valueless_by_exception()
_STD _Variant_raw_visit(
_That.index(), _STD move(_That)._Storage(), _Variant_construct_visitor<_Types...>{*this});
}
_CONSTEXPR20 void _Assign_from(const _Variant_base& _That)
noexcept(conjunction_v<is_nothrow_copy_constructible<_Types>..., is_nothrow_copy_assignable<_Types>...>) {
// copy assign _That's contained value (if any) into *this
_STD _Variant_raw_visit(_That.index(), _That._Storage(), _Variant_assign_visitor<_Types...>{*this});
}
_CONSTEXPR20 void _Assign_from(_Variant_base&& _That)
noexcept(conjunction_v<is_nothrow_move_constructible<_Types>..., is_nothrow_move_assignable<_Types>...>) {
// move assign _That's contained value (if any) into *this
_STD _Variant_raw_visit(_That.index(), _STD move(_That)._Storage(), _Variant_assign_visitor<_Types...>{*this});
}
};
template <class... _Types>
struct _Variant_destroy_layer_ : _Variant_base<_Types...> { // destruction behavior facade (non-trivial case)
using _Variant_base<_Types...>::_Variant_base;
_CONSTEXPR20 ~_Variant_destroy_layer_() noexcept { // Destroy contained value, if any
this->_Destroy();
}
_Variant_destroy_layer_() = default;
_Variant_destroy_layer_(const _Variant_destroy_layer_&) = default;
_Variant_destroy_layer_(_Variant_destroy_layer_&&) = default;
_Variant_destroy_layer_& operator=(const _Variant_destroy_layer_&) = default;
_Variant_destroy_layer_& operator=(_Variant_destroy_layer_&&) = default;
};
template <class... _Types>
using _Variant_destroy_layer = conditional_t<conjunction_v<is_trivially_destructible<_Types>...>,
_Variant_base<_Types...>, _Variant_destroy_layer_<_Types...>>;
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-volatile"
#else // ^^^ Clang / not Clang vvv
#pragma warning(push)
#pragma warning(disable : 4242) // '%s': conversion from '%s' to '%s', possible loss of data
#pragma warning(disable : 4244) // '%s': conversion from '%s' to '%s', possible loss of data (Yes, duplicated message.)
#pragma warning(disable : 4365) // '%s': conversion from '%s' to '%s', signed/unsigned mismatch
#pragma warning(disable : 5215) // '%s' a function parameter with volatile qualified type is deprecated in C++20
#endif // ^^^ not Clang ^^^
// build Ti x[] = {std::forward<T>(t)};
template <size_t _Idx, class _TargetType>
auto _Construct_array(_TargetType (&&)[1]) -> _Meta_list<integral_constant<size_t, _Idx>, _TargetType>;
template <size_t _Idx, class _TargetType, class _InitializerType>
using _Variant_type_resolver = decltype(_STD _Construct_array<_Idx, _TargetType>({_STD declval<_InitializerType>()}));
template <size_t _Idx, class _TargetType>
struct _Variant_init_single_overload {
template <class _InitializerType>
auto operator()(_TargetType, _InitializerType&&) -> _Variant_type_resolver<_Idx, _TargetType, _InitializerType>;
};
template <class _Indices, class... _Types>
struct _Variant_init_overload_set_;
template <size_t... _Indices, class... _Types>
struct _Variant_init_overload_set_<index_sequence<_Indices...>, _Types...>
: _Variant_init_single_overload<_Indices, _Types>... {
using _Variant_init_single_overload<_Indices, _Types>::operator()...;
};
template <class... _Types>
using _Variant_init_overload_set = _Variant_init_overload_set_<index_sequence_for<_Types...>, _Types...>;
template <class Enable, class _Ty, class... _Types>
struct _Variant_init_helper {}; // failure case (has no member "type")
template <class _Ty, class... _Types>
struct _Variant_init_helper<
void_t<decltype(_Variant_init_overload_set<_Types...>{}(_STD declval<_Ty>(), _STD declval<_Ty>()))>, _Ty,
_Types...> {
// perform overload resolution to determine the unique alternative that should be initialized in
// variant<_Types...> from an argument expression with type and value category _Ty
using type = decltype(_Variant_init_overload_set<_Types...>{}(_STD declval<_Ty>(), _STD declval<_Ty>()));
};
template <class _Ty, class... _Types> // extract the type from _Variant_init_helper
using _Variant_init_type = _Meta_front<_Meta_pop_front<typename _Variant_init_helper<void, _Ty, _Types...>::type>>;
template <class _Ty, class... _Types> // extract the index from _Variant_init_helper
using _Variant_init_index = _Meta_front<typename _Variant_init_helper<void, _Ty, _Types...>::type>;
#ifdef __clang__
#pragma clang diagnostic pop
#else // ^^^ Clang / not Clang vvv
#pragma warning(pop)
#endif // ^^^ not Clang ^^^
template <class>
constexpr bool _Is_in_place_index_specialization = false;
template <size_t _Idx>
constexpr bool _Is_in_place_index_specialization<in_place_index_t<_Idx>> = true;
_EXPORT_STD template <class... _Types>
class variant : private _SMF_control<_Variant_destroy_layer<_Types...>, _Types...> { // discriminated union
public:
static_assert(conjunction_v<is_object<_Types>..., negation<is_array<_Types>>..., is_destructible<_Types>...>,
"variant<Types...> requires all of the Types to meet the Cpp17Destructible requirements "
"(N4950 [variant.variant.general]/2).");
static_assert(sizeof...(_Types) > 0,
"variant<> (with no template arguments) may not be instantiated (N4950 [variant.variant.general]/3).");
using _Mybase = _SMF_control<_Variant_destroy_layer<_Types...>, _Types...>;
template <class _First = _Meta_front<variant>, enable_if_t<is_default_constructible_v<_First>, int> = 0>
constexpr variant() noexcept(is_nothrow_default_constructible_v<_First>)
: _Mybase(in_place_index<0>) {} // value-initialize alternative 0
template <class _Ty,
enable_if_t<sizeof...(_Types) != 0 && !is_same_v<_Remove_cvref_t<_Ty>, variant>
&& !_Is_specialization_v<_Remove_cvref_t<_Ty>, in_place_type_t>
&& !_Is_in_place_index_specialization<_Remove_cvref_t<_Ty>>,
int> = 0,
// These enable_if_t constraints are distinct to enable short-circuiting and avoid
// substitution into _Variant_init_type when the first constraint is not satisfied.
enable_if_t<is_constructible_v<_Variant_init_type<_Ty, _Types...>, _Ty>, int> = 0>
constexpr variant(_Ty&& _Obj) noexcept(is_nothrow_constructible_v<_Variant_init_type<_Ty, _Types...>, _Ty>)
: _Mybase(in_place_index<_Variant_init_index<_Ty, _Types...>::value>, static_cast<_Ty&&>(_Obj)) {
// initialize to the type selected by passing _Obj to the overload set f(Types)...
}
template <class _Ty, class... _UTypes, class _Idx = _Meta_find_unique_index<variant, _Ty>,
enable_if_t<_Idx::value != _Meta_npos && is_constructible_v<_Ty, _UTypes...>, int> = 0>
constexpr explicit variant(in_place_type_t<_Ty>, _UTypes&&... _Args)
noexcept(is_nothrow_constructible_v<_Ty, _UTypes...>) // strengthened
: _Mybase(in_place_index<_Idx::value>, static_cast<_UTypes&&>(_Args)...) {
// initialize alternative _Ty from _Args...
}
template <class _Ty, class _Elem, class... _UTypes, class _Idx = _Meta_find_unique_index<variant, _Ty>,
enable_if_t<_Idx::value != _Meta_npos && is_constructible_v<_Ty, initializer_list<_Elem>&, _UTypes...>, int> =
0>
constexpr explicit variant(in_place_type_t<_Ty>, initializer_list<_Elem> _Ilist, _UTypes&&... _Args)
noexcept(is_nothrow_constructible_v<_Ty, initializer_list<_Elem>&, _UTypes...>) // strengthened
: _Mybase(in_place_index<_Idx::value>, _Ilist, static_cast<_UTypes&&>(_Args)...) {
// initialize alternative _Ty from _Ilist and _Args...
}
template <size_t _Idx, class... _UTypes,
enable_if_t<is_constructible_v<_Meta_at_c<variant, _Idx>, _UTypes...>, int> = 0>
constexpr explicit variant(in_place_index_t<_Idx>, _UTypes&&... _Args)
noexcept(is_nothrow_constructible_v<_Meta_at_c<variant, _Idx>, _UTypes...>) // strengthened
: _Mybase(in_place_index<_Idx>, static_cast<_UTypes&&>(_Args)...) {
// initialize alternative _Idx from _Args...
}
template <size_t _Idx, class _Elem, class... _UTypes,
enable_if_t<is_constructible_v<_Meta_at_c<variant, _Idx>, initializer_list<_Elem>&, _UTypes...>, int> = 0>
constexpr explicit variant(in_place_index_t<_Idx>, initializer_list<_Elem> _Ilist, _UTypes&&... _Args)
noexcept(is_constructible_v<_Meta_at_c<variant, _Idx>, initializer_list<_Elem>&, _UTypes...>) // strengthened
: _Mybase(in_place_index<_Idx>, _Ilist, static_cast<_UTypes&&>(_Args)...) {
// initialize alternative _Idx from _Ilist and _Args...
}
template <class _Ty, enable_if_t<!is_same_v<_Remove_cvref_t<_Ty>, variant>, int> = 0,
// These enable_if_t constraints are distinct to enable short-circuiting and avoid
// substitution into _Variant_init_type when the first constraint is not satisfied.
enable_if_t<is_constructible_v<_Variant_init_type<_Ty, _Types...>, _Ty>
&& is_assignable_v<_Variant_init_type<_Ty, _Types...>&, _Ty>,
int> = 0>
_CONSTEXPR20 variant& operator=(_Ty&& _Obj)
noexcept(is_nothrow_assignable_v<_Variant_init_type<_Ty, _Types...>&, _Ty>
&& is_nothrow_constructible_v<_Variant_init_type<_Ty, _Types...>, _Ty>) {
// assign/emplace the alternative chosen by overload resolution of _Obj with f(_Types)...
constexpr size_t _TargetIdx = _Variant_init_index<_Ty, _Types...>::value;
if (index() == _TargetIdx) {
auto& _Target = _STD _Variant_raw_get<_TargetIdx>(_Storage());
_Target = static_cast<_Ty&&>(_Obj);
} else {
using _TargetTy = _Variant_init_type<_Ty, _Types...>;
if constexpr (_Variant_should_directly_construct_v<_TargetTy, _Ty>) {
this->_Reset();
_Emplace_valueless<_TargetIdx>(static_cast<_Ty&&>(_Obj));
} else {
_TargetTy _Temp(static_cast<_Ty&&>(_Obj));
this->_Reset();
_Emplace_valueless<_TargetIdx>(_STD move(_Temp));
}
}
return *this;
}
using _Mybase::_Storage;
template <class _Ty, class... _ArgTypes, size_t _Idx = _Meta_find_unique_index<variant, _Ty>::value,
enable_if_t<_Idx != _Meta_npos && is_constructible_v<_Ty, _ArgTypes...>, int> = 0>
_CONSTEXPR20 _Ty& emplace(_ArgTypes&&... _Args)
noexcept(is_nothrow_constructible_v<_Ty, _ArgTypes...>) /* strengthened */ {
// emplace alternative _Ty from _Args...
this->_Reset();
return _Emplace_valueless<_Idx>(static_cast<_ArgTypes&&>(_Args)...);
}
template <class _Ty, class _Elem, class... _ArgTypes, size_t _Idx = _Meta_find_unique_index<variant, _Ty>::value,
enable_if_t<_Idx != _Meta_npos && is_constructible_v<_Ty, initializer_list<_Elem>&, _ArgTypes...>, int> = 0>
_CONSTEXPR20 _Ty& emplace(initializer_list<_Elem> _Ilist, _ArgTypes&&... _Args)
noexcept(is_nothrow_constructible_v<_Ty, initializer_list<_Elem>&, _ArgTypes...>) /* strengthened */ {
// emplace alternative _Ty from _Ilist and _Args...
this->_Reset();
return _Emplace_valueless<_Idx>(_Ilist, static_cast<_ArgTypes&&>(_Args)...);
}
template <size_t _Idx, class... _ArgTypes,
enable_if_t<is_constructible_v<_Meta_at_c<variant, _Idx>, _ArgTypes...>, int> = 0>
_CONSTEXPR20 _Meta_at_c<variant, _Idx>& emplace(_ArgTypes&&... _Args)
noexcept(is_nothrow_constructible_v<_Meta_at_c<variant, _Idx>, _ArgTypes...>) /* strengthened */ {
// emplace alternative _Idx from _Args...
this->_Reset();
return _Emplace_valueless<_Idx>(static_cast<_ArgTypes&&>(_Args)...);
}
template <size_t _Idx, class _Elem, class... _ArgTypes,
enable_if_t<is_constructible_v<_Meta_at_c<variant, _Idx>, initializer_list<_Elem>&, _ArgTypes...>, int> = 0>
_CONSTEXPR20 _Meta_at_c<variant, _Idx>& emplace(initializer_list<_Elem> _Ilist, _ArgTypes&&... _Args)
noexcept(is_nothrow_constructible_v<_Meta_at_c<variant, _Idx>, initializer_list<_Elem>&,
_ArgTypes...>) /* strengthened */ {
// emplace alternative _Idx from _Ilist and _Args...
this->_Reset();
return _Emplace_valueless<_Idx>(_Ilist, static_cast<_ArgTypes&&>(_Args)...);
}
using _Mybase::index;
using _Mybase::valueless_by_exception;
#ifdef __clang__ // TRANSITION, LLVM-35450
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-lambda-capture"
#endif // ^^^ workaround ^^^
_CONSTEXPR20 void swap(variant& _That)
noexcept(conjunction_v<is_nothrow_move_constructible<_Types>..., is_nothrow_swappable<_Types>...>) {
// exchange the contained values if *this and _That hold the same alternative, otherwise exchange the values of
// the variants themselves
static_assert(conjunction_v<is_move_constructible<_Types>...>,
"variant<Types...>::swap requires all of the Types... to be move constructible. (N4950 [variant.swap]/1)");
static_assert(disjunction_v<negation<is_move_constructible<_Types>>..., conjunction<is_swappable<_Types>...>>,
"variant<Types...>::swap requires all of the Types... to be swappable. (N4950 [variant.swap]/2)");
if constexpr (conjunction_v<_Is_trivially_swappable<_Types>...>) {
using _BaseTy = _Variant_base<_Types...>;
_STD swap(static_cast<_BaseTy&>(*this), static_cast<_BaseTy&>(_That));
} else if constexpr (sizeof...(_Types) < 32) {
// Limit the size of variants that use this quadratic code size implementation of swap.
_STD _Variant_raw_visit(index(), _Storage(),
[this, &_That](auto _My_ref) noexcept(
conjunction_v<is_nothrow_move_constructible<_Types>..., is_nothrow_swappable<_Types>...>) {
_STD _Variant_raw_visit(_That.index(), _That._Storage(),
[this, &_That, _My_ref](auto _That_ref) noexcept(
conjunction_v<is_nothrow_move_constructible<_Types>..., is_nothrow_swappable<_Types>...>) {
constexpr size_t _That_idx = decltype(_That_ref)::_Idx;
constexpr size_t _My_idx = decltype(_My_ref)::_Idx;
if constexpr (_My_idx == _That_idx) { // Same alternatives...
if constexpr (_My_idx != variant_npos) { // ...and not valueless, swap directly
using _STD swap;
swap(_My_ref._Val, _That_ref._Val); // intentional ADL
}
} else if constexpr (_My_idx == variant_npos) { // *this is valueless, _That is not
this->_Emplace_valueless<_That_idx>(_STD move(_That_ref._Val));
_That.template _Reset<_That_idx>();
} else if constexpr (_That_idx == variant_npos) { // _That is valueless, *this is not
_That._Emplace_valueless<_My_idx>(_STD move(_My_ref._Val));
this->template _Reset<_My_idx>();
} else { // different non-valueless alternatives
auto _Tmp = _STD move(_My_ref._Val);
this->template _Reset<_My_idx>();
this->_Emplace_valueless<_That_idx>(_STD move(_That_ref._Val));
_That.template _Reset<_That_idx>();
_That._Emplace_valueless<_My_idx>(_STD move(_Tmp));
}
});
});
} else {
if (this->_Which == _That._Which) {
_STD _Variant_raw_visit(static_cast<size_t>(this->_Which), _That._Storage(),
[this](auto _Ref) noexcept(conjunction_v<is_nothrow_swappable<_Types>...>) {
constexpr size_t _Idx = decltype(_Ref)::_Idx;
if constexpr (_Idx != variant_npos) {
using _STD swap;
swap(_Variant_raw_get<_Idx>(this->_Storage()), _Ref._Val); // intentional ADL
}
});
} else {
variant _Tmp = _STD move(*this);
this->_Emplace_from(_STD move(_That));
_That._Emplace_from(_STD move(_Tmp));
}
}
}
#ifdef __clang__ // TRANSITION, LLVM-35450
#pragma clang diagnostic pop
#endif // ^^^ workaround ^^^
private:
template <size_t _Idx, class... _ArgTypes>
_CONSTEXPR20 _Meta_at_c<variant, _Idx>& _Emplace_valueless(_ArgTypes&&... _Args)
noexcept(is_nothrow_constructible_v<_Meta_at_c<variant, _Idx>, _ArgTypes...>) {
// initialize alternative _Idx from _Args...
_STL_INTERNAL_CHECK(valueless_by_exception());
_STD _Construct_in_place(_Storage(), integral_constant<size_t, _Idx>{}, static_cast<_ArgTypes&&>(_Args)...);
this->_Set_index(_Idx);
return _STD _Variant_raw_get<_Idx>(_Storage());
}
_CONSTEXPR20 void _Emplace_from(variant&& _That) noexcept(conjunction_v<is_nothrow_move_constructible<_Types>...>) {
// steal the contained value from _That
this->_Reset();
_STD _Variant_raw_visit(_That.index(), _That._Storage(),
[this](auto _Ref) noexcept(conjunction_v<is_nothrow_move_constructible<_Types>...>) {
constexpr size_t _Idx = decltype(_Ref)::_Idx;
if constexpr (_Idx != variant_npos) {
this->_Emplace_valueless<_Idx>(_STD move(_Ref._Val));
}
});
}
};
_EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr bool holds_alternative(const variant<_Types...>& _Var) noexcept {
// true iff _Var holds alternative _Ty
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
if constexpr (_Idx != _Meta_npos) {
return _Var.index() == _Idx;
} else {
static_assert(false, "holds_alternative<T>(const variant<Types...>&) requires T to occur exactly "
"once in Types. (N4971 [variant.get]/1)");
}
}
_EXPORT_STD template <size_t _Idx, class... _Types>
_NODISCARD constexpr decltype(auto) get(variant<_Types...>& _Var) {
// access the contained value of _Var if its _Idx-th alternative is active
static_assert(_Idx < sizeof...(_Types), "variant index out of bounds");
if (_Var.index() == _Idx) {
return _STD _Variant_raw_get<_Idx>(_Var._Storage());
}
_STD _Throw_bad_variant_access();
}
_EXPORT_STD template <size_t _Idx, class... _Types>
_NODISCARD constexpr decltype(auto) get(variant<_Types...>&& _Var) {
// access the contained value of _Var if its _Idx-th alternative is active
static_assert(_Idx < sizeof...(_Types), "variant index out of bounds");
if (_Var.index() == _Idx) {
return _STD _Variant_raw_get<_Idx>(_STD move(_Var)._Storage());
}
_STD _Throw_bad_variant_access();
}
_EXPORT_STD template <size_t _Idx, class... _Types>
_NODISCARD constexpr decltype(auto) get(const variant<_Types...>& _Var) {
// access the contained value of _Var if its _Idx-th alternative is active
static_assert(_Idx < sizeof...(_Types), "variant index out of bounds");
if (_Var.index() == _Idx) {
return _STD _Variant_raw_get<_Idx>(_Var._Storage());
}
_STD _Throw_bad_variant_access();
}
_EXPORT_STD template <size_t _Idx, class... _Types>
_NODISCARD constexpr decltype(auto) get(const variant<_Types...>&& _Var) {
// access the contained value of _Var if its _Idx-th alternative is active
static_assert(_Idx < sizeof...(_Types), "variant index out of bounds");
if (_Var.index() == _Idx) {
return _STD _Variant_raw_get<_Idx>(_STD move(_Var)._Storage());
}
_STD _Throw_bad_variant_access();
}
_EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr decltype(auto) get(variant<_Types...>& _Var) {
// access the contained value of _Var if its alternative _Ty is active
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
if constexpr (_Idx < sizeof...(_Types)) {
return _STD get<_Idx>(_Var);
} else {
static_assert(false, "get<T>(variant<Types...>&) "
"requires T to occur exactly once in Types. (N4971 [variant.get]/8)");
}
}
_EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr decltype(auto) get(variant<_Types...>&& _Var) {
// access the contained value of _Var if its alternative _Ty is active
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
if constexpr (_Idx < sizeof...(_Types)) {
return _STD get<_Idx>(_STD move(_Var));
} else {
static_assert(false, "get<T>(variant<Types...>&&) "
"requires T to occur exactly once in Types. (N4971 [variant.get]/8)");
}
}
_EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr decltype(auto) get(const variant<_Types...>& _Var) {
// access the contained value of _Var if its alternative _Ty is active
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
if constexpr (_Idx < sizeof...(_Types)) {
return _STD get<_Idx>(_Var);
} else {
static_assert(false, "get<T>(const variant<Types...>&) "
"requires T to occur exactly once in Types. (N4971 [variant.get]/8)");
}
}
_EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr decltype(auto) get(const variant<_Types...>&& _Var) {
// access the contained value of _Var if its alternative _Ty is active
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
if constexpr (_Idx < sizeof...(_Types)) {
return _STD get<_Idx>(_STD move(_Var));
} else {
static_assert(false, "get<T>(const variant<Types...>&&) "
"requires T to occur exactly once in Types. (N4971 [variant.get]/8)");
}
}
_EXPORT_STD template <size_t _Idx, class... _Types>
_NODISCARD constexpr auto get_if(variant<_Types...>* _Ptr) noexcept {
// get the address of *_Ptr's contained value if it holds alternative _Idx
static_assert(_Idx < sizeof...(_Types), "variant index out of bounds");
return _Ptr && _Ptr->index() == _Idx ? _STD addressof(_STD _Variant_raw_get<_Idx>(_Ptr->_Storage())) : nullptr;
}
_EXPORT_STD template <size_t _Idx, class... _Types>
_NODISCARD constexpr auto get_if(const variant<_Types...>* _Ptr) noexcept {
// get the address of *_Ptr's contained value if it holds alternative _Idx
static_assert(_Idx < sizeof...(_Types), "variant index out of bounds");
return _Ptr && _Ptr->index() == _Idx ? _STD addressof(_STD _Variant_raw_get<_Idx>(_Ptr->_Storage())) : nullptr;
}
_EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr add_pointer_t<_Ty> get_if(variant<_Types...>* _Ptr) noexcept {
// get the address of *_Ptr's contained value if it holds alternative _Ty
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
if constexpr (_Idx != _Meta_npos) {
return _STD get_if<_Idx>(_Ptr);
} else {
static_assert(false,
"get_if<T>(variant<Types...> *) requires T to occur exactly once in Types. (N4971 [variant.get]/12)");
}
}
_EXPORT_STD template <class _Ty, class... _Types>
_NODISCARD constexpr add_pointer_t<const _Ty> get_if(const variant<_Types...>* _Ptr) noexcept {
// get the address of *_Ptr's contained value if it holds alternative _Ty
constexpr size_t _Idx = _Meta_find_unique_index<variant<_Types...>, _Ty>::value;
if constexpr (_Idx != _Meta_npos) {
return _STD get_if<_Idx>(_Ptr);
} else {
static_assert(false,
"get_if<T>(const variant<Types...> *) requires T to occur exactly once in Types. (N4971 [variant.get]/12)");
}
}
template <class _Op, class _Result, class... _Types>
struct _Variant_relop_visitor2 { // evaluate _Op with the contained value of two variants that hold the same alternative
const _Variant_storage<_Types...>& _Left;
template <class _Ty, size_t _Idx>
_NODISCARD constexpr _Result operator()(_Tagged<const _Ty&, _Idx> _Right) const
noexcept(disjunction_v<bool_constant<_Idx == variant_npos>,
is_nothrow_invocable_r<_Result, _Op, const _Ty&, const _Ty&>>) {
// determine the relationship between the stored values of _Left and _Right
// pre: _Left.index() == _Idx && _Right.index() == _Idx
if constexpr (_Idx != variant_npos) {
return _Op{}(_STD _Variant_raw_get<_Idx>(_Left), _Right._Val);
} else { // return whatever _Op returns for equal values
return _Op{}(0, 0);
}
}
};
_EXPORT_STD template <class... _Types>
_NODISCARD constexpr bool operator==(const variant<_Types...>& _Left, const variant<_Types...>& _Right) noexcept(
conjunction_v<is_nothrow_invocable_r<bool, equal_to<>, const _Types&, const _Types&>...>) /* strengthened */ {
// determine if the arguments are both valueless or contain equal values
using _Visitor = _Variant_relop_visitor2<equal_to<>, bool, _Types...>;
const size_t _Right_index = _Right.index();
return _Left.index() == _Right_index
&& _STD _Variant_raw_visit(_Right_index, _Right._Storage(), _Visitor{_Left._Storage()});
}
_EXPORT_STD template <class... _Types>
_NODISCARD constexpr bool operator!=(const variant<_Types...>& _Left, const variant<_Types...>& _Right) noexcept(
conjunction_v<is_nothrow_invocable_r<bool, not_equal_to<>, const _Types&, const _Types&>...>) /* strengthened */ {
// determine if the arguments have different active alternatives or contain unequal values
using _Visitor = _Variant_relop_visitor2<not_equal_to<>, bool, _Types...>;
const size_t _Right_index = _Right.index();
return _Left.index() != _Right_index
|| _STD _Variant_raw_visit(_Right_index, _Right._Storage(), _Visitor{_Left._Storage()});
}
_EXPORT_STD template <class... _Types>
_NODISCARD constexpr bool operator<(const variant<_Types...>& _Left, const variant<_Types...>& _Right)
noexcept(conjunction_v<is_nothrow_invocable_r<bool, less<>, const _Types&, const _Types&>...>) /* strengthened */ {
// determine if _Left has a lesser index(), or equal index() and lesser
// contained value than _Right
using _Visitor = _Variant_relop_visitor2<less<>, bool, _Types...>;
const size_t _Left_offset = _Left.index() + 1;
const size_t _Right_offset = _Right.index() + 1;
return _Left_offset < _Right_offset
|| (_Left_offset == _Right_offset
&& _STD _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()}));
}
_EXPORT_STD template <class... _Types>
_NODISCARD constexpr bool operator>(const variant<_Types...>& _Left, const variant<_Types...>& _Right) noexcept(
conjunction_v<is_nothrow_invocable_r<bool, greater<>, const _Types&, const _Types&>...>) /* strengthened */ {
// determine if _Left has a greater index(), or equal index() and
// greater contained value than _Right
using _Visitor = _Variant_relop_visitor2<greater<>, bool, _Types...>;
const size_t _Left_offset = _Left.index() + 1;
const size_t _Right_offset = _Right.index() + 1;
return _Left_offset > _Right_offset
|| (_Left_offset == _Right_offset
&& _STD _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()}));
}
_EXPORT_STD template <class... _Types>
_NODISCARD constexpr bool operator<=(const variant<_Types...>& _Left, const variant<_Types...>& _Right) noexcept(
conjunction_v<is_nothrow_invocable_r<bool, less_equal<>, const _Types&, const _Types&>...>) /* strengthened */ {
// determine if _Left's index() is less than _Right's, or equal and
// _Left contains a value less than or equal to _Right
using _Visitor = _Variant_relop_visitor2<less_equal<>, bool, _Types...>;
const size_t _Left_offset = _Left.index() + 1;
const size_t _Right_offset = _Right.index() + 1;
return _Left_offset < _Right_offset
|| (_Left_offset == _Right_offset
&& _STD _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()}));
}
_EXPORT_STD template <class... _Types>
_NODISCARD constexpr bool operator>=(const variant<_Types...>& _Left, const variant<_Types...>& _Right) noexcept(
conjunction_v<is_nothrow_invocable_r<bool, greater_equal<>, const _Types&, const _Types&>...>) /* strengthened */ {
// determine if _Left's index() is greater than _Right's, or equal and
// _Left contains a value greater than or equal to _Right
using _Visitor = _Variant_relop_visitor2<greater_equal<>, bool, _Types...>;
const size_t _Left_offset = _Left.index() + 1;
const size_t _Right_offset = _Right.index() + 1;
return _Left_offset > _Right_offset
|| (_Left_offset == _Right_offset
&& _STD _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()}));
}
#if _HAS_CXX20
_EXPORT_STD template <class... _Types>
requires (three_way_comparable<_Types> && ...)
_NODISCARD constexpr common_comparison_category_t<compare_three_way_result_t<_Types>...> operator<=>(
const variant<_Types...>& _Left, const variant<_Types...>& _Right)
noexcept(conjunction_v<is_nothrow_invocable_r<common_comparison_category_t<compare_three_way_result_t<_Types>...>,
compare_three_way, const _Types&, const _Types&>...>) /* strengthened */ {
// determine the three-way comparison of _Left's and _Right's index, if equal
// return the three-way comparison of the contained values of _Left and _Right
using _Visitor = _Variant_relop_visitor2<compare_three_way,
common_comparison_category_t<compare_three_way_result_t<_Types>...>, _Types...>;
const size_t _Left_offset = _Left.index() + 1;
const size_t _Right_offset = _Right.index() + 1;
const auto _Offset_order = _Left_offset <=> _Right_offset;
return _Offset_order != 0
? _Offset_order
: _STD _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()});
}
#endif // _HAS_CXX20
template <class... _Variants>
constexpr size_t _Variant_total_states =
(size_t{1} * ... * (variant_size_v<_Variants> + 1)); // +1 to account for the valueless state
_NODISCARD constexpr size_t _Variant_visit_index1(const size_t _Acc) noexcept {
return _Acc;
}
template <class _FirstTy, class... _RestTys>
_NODISCARD constexpr size_t _Variant_visit_index1(
size_t _Acc, const _FirstTy& _First, const _RestTys&... _Rest) noexcept {
// calculate a canonical index from the biased indices of the variants _First and _Rest...
_Acc += (_First.index() + 1) * _Variant_total_states<_RestTys...>;
return _STD _Variant_visit_index1(_Acc, _Rest...);
}
template <class _Callable, class... _Types>
using _Variant_visit_result_t =
decltype(_STD invoke(_STD declval<_Callable>(), _STD _Variant_raw_get<0>(_STD declval<_Types>()._Storage())...));
template <class>
struct _Variant_dispatcher;
template <size_t... _Is>
struct _Variant_dispatcher<index_sequence<_Is...>> {
template <class _Ret, class _Callable, class... _Types, bool _Any_valueless = ((_Is == 0) || ...)>
_NODISCARD static constexpr _Ret _Dispatch2(_Callable&& _Obj, _Types&&... _Args) {
if constexpr (_Any_valueless) {
#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-1513409
((void) _Args, ...);
#endif // ^^^ workaround ^^^
_STD _Throw_bad_variant_access();
}
#if _HAS_CXX20
else if constexpr (is_void_v<_Ret>) {
static_cast<void>(_STD invoke(static_cast<_Callable&&>(_Obj),
_STD _Variant_raw_get<_Is - 1>(static_cast<_Types&&>(_Args)._Storage())...));
}
#endif // _HAS_CXX20
else {
return _STD invoke(static_cast<_Callable&&>(_Obj),
_STD _Variant_raw_get<_Is - 1>(static_cast<_Types&&>(_Args)._Storage())...);
}
}
};
template <class _Ret, class _Ordinals, class _Callable, class _Variants>
struct _Variant_dispatch_table; // undefined
template <class _Ret, class... _Ordinals, class _Callable, class... _Variants>
struct _Variant_dispatch_table<_Ret, _Meta_list<_Ordinals...>, _Callable, _Meta_list<_Variants...>> {
// map from canonical index to visitation target
using _Dispatch_t = _Ret (*)(_Callable&&, _Variants&&...);
static constexpr _Dispatch_t _Array[] = {
&_Variant_dispatcher<_Ordinals>::template _Dispatch2<_Ret, _Callable, _Variants...>...};
};
template <int _Strategy>
struct _Visit_strategy;
template <>
struct _Visit_strategy<-1> {
// Fallback strategy for visitations with too many total states for the following "switch" strategies.
template <class _Ret, class _ListOfIndexVectors, class _Callable, class... _Variants>
static constexpr _Ret _Visit2(
size_t _Idx, _Callable&& _Obj, _Variants&&... _Args) { // dispatch a visitation with many potential states
constexpr size_t _Size = _Variant_total_states<_Remove_cvref_t<_Variants>...>;
static_assert(_Size > 256);
constexpr auto& _Array =
_Variant_dispatch_table<_Ret, _ListOfIndexVectors, _Callable, _Meta_list<_Variants...>>::_Array;
return _Array[_Idx](static_cast<_Callable&&>(_Obj), static_cast<_Variants&&>(_Args)...);
}
};
template <>
struct _Visit_strategy<0> {
template <class _Ret, class, class _Callable>
static constexpr _Ret _Visit2(size_t, _Callable&& _Obj) { // dispatch a visitation with 4^0 potential states
if constexpr (is_void_v<_Ret>) {
return static_cast<void>(static_cast<_Callable&&>(_Obj)());
} else {
return static_cast<_Callable&&>(_Obj)();
}
}
};
#define _STL_CASE(n) \
case (n): \
if constexpr ((n) < _Size) { \
using _Indices = _Meta_at_c<_ListOfIndexVectors, (n)>; \
return _Variant_dispatcher<_Indices>::template _Dispatch2<_Ret, _Callable, _Variants...>( \
static_cast<_Callable&&>(_Obj), static_cast<_Variants&&>(_Args)...); \
} \
_STL_UNREACHABLE; \
[[fallthrough]]
#define _STL_VISIT_STAMP(stamper, n) \
constexpr size_t _Size = _Variant_total_states<_Remove_cvref_t<_Variants>...>; \
static_assert(_Size > (n) / 4 && _Size <= (n)); \
switch (_Idx) { \
stamper(0, _STL_CASE); \
default: \
_STL_UNREACHABLE; \
}
template <>
struct _Visit_strategy<1> {
template <class _Ret, class _ListOfIndexVectors, class _Callable, class... _Variants>
static constexpr _Ret _Visit2(size_t _Idx, _Callable&& _Obj, _Variants&&... _Args) {
// dispatch a visitation with 4^1 potential states
_STL_STAMP(4, _STL_VISIT_STAMP);
}
};
template <>
struct _Visit_strategy<2> {
template <class _Ret, class _ListOfIndexVectors, class _Callable, class... _Variants>
static constexpr _Ret _Visit2(size_t _Idx, _Callable&& _Obj, _Variants&&... _Args) {
// dispatch a visitation with 4^2 potential states
_STL_STAMP(16, _STL_VISIT_STAMP);
}
};
template <>
struct _Visit_strategy<3> {
template <class _Ret, class _ListOfIndexVectors, class _Callable, class... _Variants>
static constexpr _Ret _Visit2(size_t _Idx, _Callable&& _Obj, _Variants&&... _Args) {
// dispatch a visitation with 4^3 potential states
_STL_STAMP(64, _STL_VISIT_STAMP);
}
};
template <>
struct _Visit_strategy<4> {
template <class _Ret, class _ListOfIndexVectors, class _Callable, class... _Variants>
static constexpr _Ret _Visit2(size_t _Idx, _Callable&& _Obj, _Variants&&... _Args) {
// dispatch a visitation with 4^4 potential states
_STL_STAMP(256, _STL_VISIT_STAMP);
}
};
#undef _STL_VISIT_STAMP
#undef _STL_CASE
template <class... _Types>
variant<_Types...>& _As_variant_impl(variant<_Types...>&);
template <class... _Types>
const variant<_Types...>& _As_variant_impl(const variant<_Types...>&);
template <class... _Types>
variant<_Types...>&& _As_variant_impl(variant<_Types...>&&);
template <class... _Types>
const variant<_Types...>&& _As_variant_impl(const variant<_Types...>&&);
template <class _Ty>
using _As_variant = // Deduce variant specialization from a derived type
decltype(_STD _As_variant_impl(_STD declval<_Ty>()));
template <size_t _Size, class _Ret, class _ListOfIndexVectors, class _Callable, class... _Variants>
constexpr _Ret _Visit_impl(_Callable&& _Obj, _Variants&&... _Args) {
constexpr int _Strategy = _Size == 1 ? 0
: _Size <= 4 ? 1
: _Size <= 16 ? 2
: _Size <= 64 ? 3
: _Size <= 256 ? 4
: -1;
return _Visit_strategy<_Strategy>::template _Visit2<_Ret, _ListOfIndexVectors>(
_STD _Variant_visit_index1(0, static_cast<_As_variant<_Variants>&>(_Args)...), static_cast<_Callable&&>(_Obj),
static_cast<_As_variant<_Variants>&&>(_Args)...);
}
template <class _Expected, class _Callable, class _ArgList, class... _Variants>
constexpr bool _Variant_all_visit_results_same = false;
template <class _Expected, class _Callable, class... _Args>
constexpr bool _Variant_all_visit_results_same<_Expected, _Callable, _Meta_list<_Args...>> =
is_same_v<decltype(_STD invoke(_STD declval<_Callable>(), _STD declval<_Args>()...)), _Expected>;
template <class _Expected, class _Callable, class... _Args, class... _Types, class... _Rest>
constexpr bool
_Variant_all_visit_results_same<_Expected, _Callable, _Meta_list<_Args...>, variant<_Types...>&, _Rest...> =
(_Variant_all_visit_results_same<_Expected, _Callable, _Meta_list<_Args..., _Types&>, _Rest...> && ...);
template <class _Expected, class _Callable, class... _Args, class... _Types, class... _Rest>
constexpr bool
_Variant_all_visit_results_same<_Expected, _Callable, _Meta_list<_Args...>, const variant<_Types...>&, _Rest...> =
(_Variant_all_visit_results_same<_Expected, _Callable, _Meta_list<_Args..., const _Types&>, _Rest...> && ...);
template <class _Expected, class _Callable, class... _Args, class... _Types, class... _Rest>
constexpr bool
_Variant_all_visit_results_same<_Expected, _Callable, _Meta_list<_Args...>, variant<_Types...>&&, _Rest...> =
(_Variant_all_visit_results_same<_Expected, _Callable, _Meta_list<_Args..., _Types>, _Rest...> && ...);
template <class _Expected, class _Callable, class... _Args, class... _Types, class... _Rest>
constexpr bool
_Variant_all_visit_results_same<_Expected, _Callable, _Meta_list<_Args...>, const variant<_Types...>&&, _Rest...> =
(_Variant_all_visit_results_same<_Expected, _Callable, _Meta_list<_Args..., const _Types>, _Rest...> && ...);
_EXPORT_STD template <class _Callable, class... _Variants, class = void_t<_As_variant<_Variants>...>>
constexpr _Variant_visit_result_t<_Callable, _As_variant<_Variants>...> visit(_Callable&& _Obj, _Variants&&... _Args) {
// Invoke _Obj with the contained values of _Args...
constexpr auto _Size = _Variant_total_states<_Remove_cvref_t<_As_variant<_Variants>>...>;
using _ListOfIndexLists =
_Meta_list<_Meta_as_list<make_index_sequence<1 + variant_size_v<_Remove_cvref_t<_As_variant<_Variants>>>>>...>;
using _ListOfIndexVectors =
_Meta_transform<_Meta_quote<_Meta_as_integer_sequence>, _Meta_cartesian_product<_ListOfIndexLists>>;
using _Ret = _Variant_visit_result_t<_Callable, _As_variant<_Variants>...>;
static_assert(_Variant_all_visit_results_same<_Ret, _Callable, _Meta_list<>, _As_variant<_Variants>...>,
"visit() requires the result of all potential invocations to have the same type and value category "
"(N4950 [variant.visit]/5).");
return _STD _Visit_impl<_Size, _Ret, _ListOfIndexVectors>(
static_cast<_Callable&&>(_Obj), static_cast<_Variants&&>(_Args)...);
}
#if _HAS_CXX20
template <class _Expected, class _Callable, class _ArgList, class... _Variants>
constexpr bool _Variant_all_visit_results_convertible = false;
template <class _Expected, class _Callable, class... _Args>
constexpr bool _Variant_all_visit_results_convertible<_Expected, _Callable, _Meta_list<_Args...>> =
_Invoke_convertible<decltype(_STD invoke(_STD declval<_Callable>(), _STD declval<_Args>()...)), _Expected>::value;
template <class _Expected, class _Callable, class... _Args, class... _Types, class... _Rest>
constexpr bool
_Variant_all_visit_results_convertible<_Expected, _Callable, _Meta_list<_Args...>, variant<_Types...>&, _Rest...> =
(_Variant_all_visit_results_convertible<_Expected, _Callable, _Meta_list<_Args..., _Types&>, _Rest...> && ...);
template <class _Expected, class _Callable, class... _Args, class... _Types, class... _Rest>
constexpr bool _Variant_all_visit_results_convertible<_Expected, _Callable, _Meta_list<_Args...>,
const variant<_Types...>&, _Rest...> =
(_Variant_all_visit_results_convertible<_Expected, _Callable, _Meta_list<_Args..., const _Types&>, _Rest...>
&& ...);
template <class _Expected, class _Callable, class... _Args, class... _Types, class... _Rest>
constexpr bool
_Variant_all_visit_results_convertible<_Expected, _Callable, _Meta_list<_Args...>, variant<_Types...>&&, _Rest...> =
(_Variant_all_visit_results_convertible<_Expected, _Callable, _Meta_list<_Args..., _Types>, _Rest...> && ...);
template <class _Expected, class _Callable, class... _Args, class... _Types, class... _Rest>
constexpr bool _Variant_all_visit_results_convertible<_Expected, _Callable, _Meta_list<_Args...>,
const variant<_Types...>&&, _Rest...> =
(_Variant_all_visit_results_convertible<_Expected, _Callable, _Meta_list<_Args..., const _Types>, _Rest...> && ...);
_EXPORT_STD template <class _Ret, class _Callable, class... _Variants, class = void_t<_As_variant<_Variants>...>>
constexpr _Ret visit(_Callable&& _Obj, _Variants&&... _Args) {
constexpr auto _Size = _Variant_total_states<_Remove_cvref_t<_As_variant<_Variants>>...>;
using _ListOfIndexLists =
_Meta_list<_Meta_as_list<make_index_sequence<1 + variant_size_v<_Remove_cvref_t<_As_variant<_Variants>>>>>...>;
using _ListOfIndexVectors =
_Meta_transform<_Meta_quote<_Meta_as_integer_sequence>, _Meta_cartesian_product<_ListOfIndexLists>>;
if constexpr (!is_void_v<_Ret>) {
static_assert(_Variant_all_visit_results_convertible<_Ret, _Callable, _Meta_list<>, _As_variant<_Variants>...>,
"visit<R>() requires the result of all potential invocations to be implicitly convertible to R "
"(N4950 [variant.visit]/5).");
}
return _STD _Visit_impl<_Size, _Ret, _ListOfIndexVectors>(
static_cast<_Callable&&>(_Obj), static_cast<_Variants&&>(_Args)...);
}
#endif // _HAS_CXX20
_EXPORT_STD _NODISCARD constexpr bool operator==(monostate, monostate) noexcept {
return true;
}
#if _HAS_CXX20
_EXPORT_STD _NODISCARD constexpr strong_ordering operator<=>(monostate, monostate) noexcept {
return strong_ordering::equal;
}
#else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv
_NODISCARD constexpr bool operator!=(monostate, monostate) noexcept {
return false;
}
_NODISCARD constexpr bool operator<(monostate, monostate) noexcept {
return false;
}
_NODISCARD constexpr bool operator>(monostate, monostate) noexcept {
return false;
}
_NODISCARD constexpr bool operator<=(monostate, monostate) noexcept {
return true;
}
_NODISCARD constexpr bool operator>=(monostate, monostate) noexcept {
return true;
}
#endif // ^^^ !_HAS_CXX20 ^^^
_EXPORT_STD template <class... _Types,
enable_if_t<conjunction_v<is_move_constructible<_Types>..., is_swappable<_Types>...>, int> = 0>
_CONSTEXPR20 void swap(variant<_Types...>& _Left, variant<_Types...>& _Right) noexcept(noexcept(_Left.swap(_Right))) {
_Left.swap(_Right);
}
struct _Variant_hash_visitor { // visitation function for hashing variants
template <class _Ty, size_t _Idx>
_NODISCARD _STATIC_CALL_OPERATOR size_t operator()(_Tagged<const _Ty&, _Idx> _Obj) _CONST_CALL_OPERATOR
noexcept(disjunction_v<bool_constant<_Idx == variant_npos>,
is_nothrow_invocable<hash<_Ty>, const _Ty&>>) { // hash contained value _Obj
if constexpr (_Idx == variant_npos) { // hash a valueless variant
return 0;
} else { // hash the contained value
return hash<_Ty>{}(_Obj._Val);
}
}
};
template <class... _Types>
struct hash<variant<_Types...>> : _Conditionally_enabled_hash<variant<_Types...>,
conjunction_v<is_default_constructible<hash<remove_const_t<_Types>>>...>> {
_NODISCARD static size_t _Do_hash(const variant<_Types...>& _Var)
noexcept(conjunction_v<_Is_nothrow_hashable<remove_const_t<_Types>>...>) {
// called from the CRTP base to hash _Var iff the hash is enabled
return _STD _Variant_raw_visit(_Var.index(), _Var._Storage(), _Variant_hash_visitor{});
}
};
template <>
struct hash<monostate> {
using _ARGUMENT_TYPE_NAME _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS = monostate;
using _RESULT_TYPE_NAME _CXX17_DEPRECATE_ADAPTOR_TYPEDEFS = size_t;
_NODISCARD _STATIC_CALL_OPERATOR size_t operator()(monostate) _CONST_CALL_OPERATOR noexcept {
return 1729; // Arbitrary value
}
};
_STD_END
#undef _STL_STAMP
#undef _STL_STAMP256
#undef _STL_STAMP64
#undef _STL_STAMP16
#undef _STL_STAMP4
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // ^^^ _HAS_CXX17 ^^^
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _VARIANT_