STL/stl/inc/variant

1803 строки
84 KiB
C++

// variant standard header
// Copyright (c) Microsoft Corporation.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#pragma once
#ifndef _VARIANT_
#define _VARIANT_
#include <yvals.h>
#if _STL_COMPILER_PREPROCESSOR
#if !_HAS_CXX17
#pragma message("The contents of <variant> are available only with C++17 or later.")
#else // ^^^ !_HAS_CXX17 / _HAS_CXX17 vvv
#include <exception>
#include <initializer_list>
#include <type_traits>
#include <utility>
#include <xmemory>
#include <xsmf_control.h>
#include <xstddef>
#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
#ifdef __clang__
#define _STL_UNREACHABLE __builtin_unreachable()
#else // ^^^ clang ^^^ / vvv other vvv
#define _STL_UNREACHABLE __assume(false)
#endif // __clang__
_STD_BEGIN
// TYPE TRAITS
template <class...>
struct _All_same : true_type {};
template <class _First, class... _Rest>
struct _All_same<_First, _Rest...> : bool_constant<conjunction_v<is_same<_First, _Rest>...>> {}; // variadic is_same
template <class _To, class... _From>
struct _Convertible_from_all : bool_constant<conjunction_v<is_convertible<_From, _To>...>> {
// variadic is_convertible
};
// METAPROGRAMMING UTILITIES
template <class...>
struct _Meta_list {}; // a sequence of types
struct _Meta_nil {};
// ALIAS TEMPLATE _Meta_front
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;
};
// ALIAS TEMPLATE _Meta_pop_front
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...>;
};
// ALIAS TEMPLATE _Meta_push_front
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...>;
};
// STRUCT TEMPLATE _Meta_quote
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;
};
// ALIAS TEMPLATE _Meta_invoke
template <class _Fn, class... _Args>
using _Meta_invoke = // invoke meta-callable _Fn with _Args
typename _Fn::template _Invoke<_Args...>;
// STRUCT TEMPLATE _Meta_bind_back
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...>;
};
// ALIAS TEMPLATE _Meta_apply
template <class _Fn, class _List>
struct _Meta_apply_;
template <class _Fn, class _List>
using _Meta_apply =
// explode _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>...>;
};
// ALIAS TEMPLATE _Meta_transform
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>...>;
};
// ALIAS TEMPLATE _Meta_repeat_n_c
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>...>;
};
// ALIAS TEMPLATE _Meta_at_c
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 // ^^^ __clang__ / !__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 // __clang__
// ALIAS TEMPLATE _Meta_find_index
inline constexpr auto _Meta_npos = ~size_t{0};
template <class _List, class _Ty>
struct _Meta_find_index_ {
using type = integral_constant<size_t, _Meta_npos>;
};
template <class _List, class _Ty>
using _Meta_find_index =
// find the index of the first occurrence of _Ty in _List
typename _Meta_find_index_<_List, _Ty>::type;
constexpr size_t _Meta_find_index_i_(const bool* const _Ptr, const size_t _Count,
size_t _Idx = 0) { // return the index of the first true in the _Count bools at _Ptr, or _Meta_npos if all are false
for (; _Idx < _Count; ++_Idx) {
if (_Ptr[_Idx]) {
return _Idx;
}
}
return _Meta_npos;
}
template <template <class...> class _List, class _First, class... _Rest, class _Ty>
struct _Meta_find_index_<_List<_First, _Rest...>, _Ty> {
static constexpr bool _Bools[] = {is_same_v<_First, _Ty>, is_same_v<_Rest, _Ty>...};
using type = integral_constant<size_t, _Meta_find_index_i_(_Bools, 1 + sizeof...(_Rest))>;
};
// ALIAS TEMPLATE _Meta_find_unique_index
template <class _List, class _Ty>
struct _Meta_find_unique_index_ {
using type = integral_constant<size_t, _Meta_npos>;
};
template <class _List, class _Ty>
using _Meta_find_unique_index =
// The index of _Ty in _List if it occurs exactly once, otherwise _Meta_npos
typename _Meta_find_unique_index_<_List, _Ty>::type;
constexpr size_t _Meta_find_unique_index_i_2(const bool* const _Ptr, const size_t _Count,
const size_t
_First) { // return _First if there is no _First < j < _Count such that _Ptr[j] is true, otherwise _Meta_npos
return _First != _Meta_npos && _Meta_find_index_i_(_Ptr, _Count, _First + 1) == _Meta_npos ? _First : _Meta_npos;
}
constexpr size_t _Meta_find_unique_index_i_(const bool* const _Ptr,
const size_t _Count) { // Pass the smallest i such that _Ptr[i] is true to _Meta_find_unique_index_i_2
return _Meta_find_unique_index_i_2(_Ptr, _Count, _Meta_find_index_i_(_Ptr, _Count));
}
template <template <class...> class _List, class _First, class... _Rest, class _Ty>
struct _Meta_find_unique_index_<_List<_First, _Rest...>, _Ty> {
using type = integral_constant<size_t,
_Meta_find_unique_index_i_(_Meta_find_index_<_List<_First, _Rest...>, _Ty>::_Bools, 1 + sizeof...(_Rest))>;
};
// ALIAS TEMPLATE _Meta_as_list
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>...>;
};
// ALIAS TEMPLATE _Meta_as_integer_sequence
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...>;
};
// ALIAS TEMPLATE _Meta_concat
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...>;
};
// ALIAS TEMPLATE _Meta_join
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>;
// ALIAS TEMPLATE _Meta_cartesian_product
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)
// VARIANT OF VALUE TYPES [variant.variant]
template <class... _Types>
class variant;
// VARIANT HELPER CLASSES [variant.helper]
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 {};
template <class _Ty>
inline constexpr size_t variant_size_v = variant_size<_Ty>::value;
template <class... _Types>
struct variant_size<variant<_Types...>> : integral_constant<size_t, sizeof...(_Types)> {};
template <size_t _Idx, class _Ty>
struct variant_alternative; // undefined
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 // ^^^ __clang__ ^^^ / vvv !__clang__ vvv
using type = _Meta_at_c<variant<_Types...>, _Idx>;
#endif // __clang__
};
inline constexpr size_t variant_npos = _Meta_npos;
// CLASS bad_variant_access [variant.bad.access]
class bad_variant_access
: public exception { // exception for visit of a valueless variant or get<I> on a variant with index() != I
public:
bad_variant_access() noexcept = default;
_NODISCARD virtual const char* __CLR_OR_THIS_CALL what() const noexcept override {
return "bad variant access";
}
#if !_HAS_EXCEPTIONS
protected:
virtual void _Doraise() const override { // perform class-specific exception handling
_RAISE(*this);
}
#endif // !_HAS_EXCEPTIONS
};
[[noreturn]] inline void _Throw_bad_variant_access() {
_THROW(bad_variant_access{});
}
template <bool _TrivialDestruction, class... _Types>
class _Variant_storage_ {}; // empty storage (empty "_Types" case)
// ALIAS TEMPLATE _Variant_storage
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_const_t<_First> _Head;
_Variant_storage<_Rest...> _Tail;
};
_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_const_t<_First> _Head;
_Variant_storage<_Rest...> _Tail;
};
~_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)
}
_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_const_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;
};
~_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)
}
_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 // __cplusplus_winrt
// _Variant_storage VISITATION AND ACCESS
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 _Variant_raw_get<_Idx - 8>(
static_cast<_Storage&&>(_Obj)._Tail._Tail._Tail._Tail._Tail._Tail._Tail._Tail);
} else if constexpr (_Idx < 32) {
return _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 _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 _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(_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>{_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>>
inline constexpr bool _Variant_raw_visit_noexcept = false;
template <class _Fn, class _Storage, size_t... _Idxs>
inline 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[] = {
&_Variant_raw_visit_valueless<_Fn, _Storage>, &_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)>{_Variant_raw_get<(n)>(static_cast<_Storage&&>(_Obj))}); \
} \
_STL_UNREACHABLE
#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));
}
// STRUCT TEMPLATE _Variant_base
template <class...>
class _Variant_base;
template <size_t _Count>
using _Variant_index_t = // signed so that conversion of -1 to size_t can cheaply sign extend
conditional_t<(_Count < static_cast<size_t>((numeric_limits<signed char>::max) ())), signed char,
conditional_t<(_Count < static_cast<size_t>((numeric_limits<short>::max) ())), 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>
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
// pre: _Self.valueless_by_exception()
(void) _Source; // TRANSITION, DevCom-1004719
if constexpr (_Idx != variant_npos) {
auto& _Target = _Variant_raw_get<_Idx>(_Self._Storage());
_Construct_in_place(_Target, static_cast<_Ty&&>(_Source._Val));
_Self._Set_index(_Idx);
}
}
};
template <class _Target, class... _Types>
inline 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>
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
(void) _Source; // TRANSITION, DevCom-1004719
_Self._Reset();
} else {
auto& _Target = _Variant_raw_get<_Idx>(_Self._Storage());
if (_Self._Which == _Idx) { // same alternative: assign directly
_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();
_Construct_in_place(_Target, _Source._Val);
} else { // copy throws and move does not; move from a temporary copy
auto _Temp = _Source._Val;
_Self._Reset();
_Construct_in_place(_Target, _STD move(_Temp));
}
} else { // RHS is an rvalue: move
_Self._Reset();
_Construct_in_place(_Target, static_cast<_Ty&&>(_Source._Val));
}
_Self._Set_index(_Idx);
}
}
}
};
template <class... _Types>
class _Variant_base
: private _Variant_storage<_Types...> { // Associate an integral discriminator with a _Variant_storage
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);
}
_Variant_base() noexcept : _Storage_t{}, _Which{_Invalid_index} {} // initialize to the value-less state
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);
}
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>
void _Destroy() noexcept {
// destroy the contained value
// pre: _Idx == index()
if constexpr (_Idx != variant_npos && !is_trivially_destructible_v<_Meta_at_c<variant<_Types...>, _Idx>>) {
_Destroy_in_place(_Variant_raw_get<_Idx>(_Storage()));
}
}
void _Destroy() noexcept { // destroy the contained value, if any
if constexpr (!conjunction_v<is_trivially_destructible<_Types>...>) {
_Variant_raw_visit(index(), _Storage(), [](auto _Ref) noexcept {
if constexpr (decltype(_Ref)::_Idx != variant_npos) {
_Destroy_in_place(_Ref._Val);
}
});
}
}
void _Reset() noexcept { // transition to the valueless_by_exception state
_Destroy();
_Set_index(variant_npos);
}
template <size_t _Idx>
void _Reset() noexcept {
// transition to the valueless_by_exception state
// pre: _Idx == index()
if constexpr (_Idx != variant_npos) {
_Destroy<_Idx>();
_Set_index(variant_npos);
}
}
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()
_Variant_raw_visit(_That.index(), _That._Storage(), _Variant_construct_visitor<_Types...>{*this});
}
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()
_Variant_raw_visit(_That.index(), _STD move(_That)._Storage(), _Variant_construct_visitor<_Types...>{*this});
}
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
_Variant_raw_visit(_That.index(), _That._Storage(), _Variant_assign_visitor<_Types...>{*this});
}
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
_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;
~_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...>>;
// CLASS TEMPLATE variant
#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 // __clang__
#if _HAS_CXX20
// 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(_Construct_array<_Idx, _TargetType>({_STD declval<_InitializerType>()}));
#endif // _HAS_CXX20
template <size_t _Idx, class _TargetType>
struct _Variant_init_single_overload {
#if _HAS_CXX20
template <class _InitializerType>
auto operator()(_TargetType, _InitializerType&&) -> _Variant_type_resolver<_Idx, _TargetType, _InitializerType>;
#else // _HAS_CXX20
template <class _InitializerType>
auto operator()(_TargetType, _InitializerType&&) -> _Meta_list<integral_constant<size_t, _Idx>, _TargetType>;
#endif // _HAS_CXX20
};
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 // __clang__
template <class>
inline constexpr bool _Is_in_place_index_specialization = false;
template <size_t _Idx>
inline constexpr bool _Is_in_place_index_specialization<in_place_index_t<_Idx>> = true;
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 "
"N4828 [variant.variant]/2.");
static_assert(sizeof...(_Types) > 0,
"variant<> (with no template arguments) may not be instantiated (N4835 [variant.variant]/3).");
using _Mybase = _SMF_control<_Variant_destroy_layer<_Types...>, _Types...>;
// constructors [variant.ctor]
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>> //
&& 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...
}
// assignment [variant.assign]
template <class _Ty, enable_if_t<!is_same_v<_Remove_cvref_t<_Ty>, variant> //
&& is_constructible_v<_Variant_init_type<_Ty, _Types...>, _Ty> //
&& is_assignable_v<_Variant_init_type<_Ty, _Types...>&, _Ty>, //
int> = 0>
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 = _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;
}
// modifiers [variant.mod]
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>
_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>
_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>
_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>
_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)...);
}
// value status [variant.status]
using _Mybase::index;
using _Mybase::valueless_by_exception;
// swap [variant.swap]
#ifdef __clang__ // TRANSITION, LLVM-45398
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-lambda-capture"
#endif // TRANSITION, LLVM-45398
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. (N4835 [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. (N4835 [variant.swap]/1)");
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.
_Variant_raw_visit(index(), _Storage(),
[this, &_That](auto _My_ref) noexcept(
conjunction_v<is_nothrow_move_constructible<_Types>..., is_nothrow_swappable<_Types>...>) {
_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;
#ifdef __EDG__ // TRANSITION, VSO-657455
constexpr size_t _My_idx = decltype(_My_ref)::_Idx + 0 * _That_idx;
#else // ^^^ workaround ^^^ / vvv no workaround vvv
constexpr size_t _My_idx = decltype(_My_ref)::_Idx;
#endif // TRANSITION, VSO-657455
if constexpr (_My_idx == _That_idx) { // Same alternatives...
if constexpr (_My_idx != variant_npos) { // ...and not valueless, swap directly
_Swap_adl(_My_ref._Val, _That_ref._Val);
}
} 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
#ifdef __EDG__ // TRANSITION, VSO-657455
using _Workaround = enable_if_t<_That_idx != variant_npos, decltype(_My_ref._Val)>;
auto _Tmp = _STD move(static_cast<_Workaround>(_My_ref._Val));
#else // ^^^ workaround ^^^ / vvv no workaround vvv
auto _Tmp = _STD move(_My_ref._Val);
#endif // TRANSITION, VSO-657455
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) {
_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) {
_Swap_adl(_Variant_raw_get<_Idx>(this->_Storage()), _Ref._Val);
}
});
} else {
variant _Tmp = _STD move(*this);
this->_Emplace_from(_STD move(_That));
_That._Emplace_from(_STD move(_Tmp));
}
}
}
#ifdef __clang__ // TRANSITION, LLVM-45398
#pragma clang diagnostic pop
#endif // TRANSITION, LLVM-45398
private:
template <size_t _Idx, class... _ArgTypes>
_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...
// pre: valueless_by_exception()
auto& _Obj = _Variant_raw_get<_Idx>(_Storage());
_Construct_in_place(_Obj, static_cast<_ArgTypes&&>(_Args)...);
this->_Set_index(_Idx);
return _Obj;
}
void _Emplace_from(variant&& _That) noexcept(conjunction_v<is_nothrow_move_constructible<_Types>...>) {
// steal the contained value from _That
this->_Reset();
_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));
}
});
}
};
// VALUE ACCESS [variant.get]
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;
static_assert(_Idx != _Meta_npos, "holds_alternative<T>(const variant<Types...>&) requires T to occur exactly "
"once in Types. (N4835 [variant.get]/1)");
return _Var.index() == _Idx;
}
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 _Variant_raw_get<_Idx>(_Var._Storage());
}
_Throw_bad_variant_access();
}
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 _Variant_raw_get<_Idx>(_STD move(_Var)._Storage());
}
_Throw_bad_variant_access();
}
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 _Variant_raw_get<_Idx>(_Var._Storage());
}
_Throw_bad_variant_access();
}
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 _Variant_raw_get<_Idx>(_STD move(_Var)._Storage());
}
_Throw_bad_variant_access();
}
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;
static_assert(_Idx < sizeof...(_Types),
"get<T>(variant<Types...>&) requires T to occur exactly once in Types. (N4835 [variant.get]/5)");
return _STD get<_Idx>(_Var);
}
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;
static_assert(_Idx < sizeof...(_Types),
"get<T>(variant<Types...>&&) requires T to occur exactly once in Types. (N4835 [variant.get]/5)");
return _STD get<_Idx>(_STD move(_Var));
}
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;
static_assert(_Idx < sizeof...(_Types),
"get<T>(const variant<Types...>&) requires T to occur exactly once in Types. (N4835 [variant.get]/5)");
return _STD get<_Idx>(_Var);
}
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;
static_assert(_Idx < sizeof...(_Types),
"get<T>(const variant<Types...>&&) requires T to occur exactly once in Types. (N4835 [variant.get]/5)");
return _STD get<_Idx>(_STD move(_Var));
}
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(_Variant_raw_get<_Idx>(_Ptr->_Storage())) : nullptr;
}
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(_Variant_raw_get<_Idx>(_Ptr->_Storage())) : nullptr;
}
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;
static_assert(_Idx != _Meta_npos,
"get_if<T>(variant<Types...> *) requires T to occur exactly once in Types. (N4835 [variant.get]/9)");
return _STD get_if<_Idx>(_Ptr);
}
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;
static_assert(_Idx != _Meta_npos,
"get_if<T>(const variant<Types...> *) requires T to occur exactly once in Types. (N4835 [variant.get]/9)");
return _STD get_if<_Idx>(_Ptr);
}
// RELATIONAL OPERATORS [variant.relops]
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{}(_Variant_raw_get<_Idx>(_Left), _Right._Val);
} else { // return whatever _Op returns for equal values
(void) _Right; // TRANSITION, DevCom-1004719
return _Op{}(0, 0);
}
}
};
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
&& _Variant_raw_visit(_Right_index, _Right._Storage(), _Visitor{_Left._Storage()});
}
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
|| _Variant_raw_visit(_Right_index, _Right._Storage(), _Visitor{_Left._Storage()});
}
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
&& _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()}));
}
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
&& _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()}));
}
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
&& _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()}));
}
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
&& _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()}));
}
#ifdef __cpp_lib_concepts
// clang-format off
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 */ {
// clang-format on
// 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
: _Variant_raw_visit(_Right_offset - 1, _Right._Storage(), _Visitor{_Left._Storage()});
}
#endif // __cpp_lib_concepts
// VISITATION [variant.visit]
template <class... _Variants>
inline 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 _Variant_visit_index1(_Acc, _Rest...);
}
template <class _Callable, class... _Types>
using _Variant_visit_result_t =
decltype(_STD invoke(_STD declval<_Callable>(), _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) {
(void) _Obj; // TRANSITION, DevCom-1004719
((void) _Args, ...); // TRANSITION, DevCom-1004719
_Throw_bad_variant_access();
}
#if _HAS_CXX20
else if constexpr (is_void_v<_Ret>) {
static_cast<void>(_STD invoke(
static_cast<_Callable&&>(_Obj), _Variant_raw_get<_Is - 1>(static_cast<_Types&&>(_Args)._Storage())...));
}
#endif // _HAS_CXX20
else {
return _STD invoke(
static_cast<_Callable&&>(_Obj), _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 <class _Callable, class _IndexSequence, class... _Variants>
struct _Variant_single_visit_result; // undefined
template <class _Callable, size_t... _Idxs, class... _Variants>
struct _Variant_single_visit_result<_Callable, index_sequence<_Idxs...>,
_Variants...> { // result type/category from invoking _Callable with the elements of
// _Variants... at (_Idxs - 1)...
using type = decltype(_STD invoke(_STD declval<_Callable>(),
_Variant_raw_get<_Idxs == 0 ? 0 : _Idxs - 1>(_STD declval<_Variants>()._Storage())...));
};
template <class _Callable, class _ListOfIndexVectors, class... _Variants>
struct _Variant_all_visit_results_same; // undefined
template <class _Callable, class... _IndexVectors, class... _Variants>
struct _Variant_all_visit_results_same<_Callable, _Meta_list<_IndexVectors...>, _Variants...>
: _All_same<typename _Variant_single_visit_result<_Callable, _IndexVectors,
_Variants...>::type...>::type { // true_type iff invocation of _Callable on the elements of _Variants with all
// sequences of indices in _IndexVectors has the same type and value category.
};
template <class _To, class _Callable, class _ListOfIndexVectors, class... _Variants>
struct _Variant_all_visit_results_implicitly_convertible; // undefined
template <class _To, class _Callable, class... _IndexVectors, class... _Variants>
struct _Variant_all_visit_results_implicitly_convertible<_To, _Callable, _Meta_list<_IndexVectors...>, _Variants...>
: _Convertible_from_all<_To,
typename _Variant_single_visit_result<_Callable, _IndexVectors, _Variants...>::type...>::type {
// true_type if invocation of _Callable on the elements of _Variants with all sequences of indices in _IndexVectors
// is implicitly convertible to _To.
};
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
#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_(variant<_Types...>&);
template <class... _Types>
const variant<_Types...>& _As_variant_(const variant<_Types...>&);
template <class... _Types>
variant<_Types...>&& _As_variant_(variant<_Types...>&&);
template <class... _Types>
const variant<_Types...>&& _As_variant_(const variant<_Types...>&&);
template <class _Ty>
using _As_variant = // Deduce variant specialization from a derived type
decltype(_As_variant_(_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>(
_Variant_visit_index1(0, static_cast<_As_variant<_Variants>&>(_Args)...), static_cast<_Callable&&>(_Obj),
static_cast<_As_variant<_Variants>&&>(_Args)...);
}
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<_Callable, _ListOfIndexVectors, _As_variant<_Variants>...>::value,
"visit() requires the result of all potential invocations to have the same type and value category "
"(N4835 [variant.visit]/2).");
return _Visit_impl<_Size, _Ret, _ListOfIndexVectors>(
static_cast<_Callable&&>(_Obj), static_cast<_Variants&&>(_Args)...);
}
#if _HAS_CXX20
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_implicitly_convertible<_Ret, _Callable, _ListOfIndexVectors,
_As_variant<_Variants>...>::value,
"visit<R>() requires the result of all potential invocations to be implicitly convertible to R "
"(N4835 [variant.visit]/2).");
}
return _Visit_impl<_Size, _Ret, _ListOfIndexVectors>(
static_cast<_Callable&&>(_Obj), static_cast<_Variants&&>(_Args)...);
}
#endif // _HAS_CXX20
// monostate RELATIONAL OPERATORS [variant.monostate.relops]
_NODISCARD constexpr bool operator==(monostate, monostate) noexcept {
return true;
}
#if _HAS_CXX20
_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
// SPECIALIZED ALGORITHMS [variant.specalg]
template <class... _Types,
enable_if_t<conjunction_v<is_move_constructible<_Types>..., is_swappable<_Types>...>, int> = 0>
void swap(variant<_Types...>& _Left, variant<_Types...>& _Right) noexcept(noexcept(_Left.swap(_Right))) {
_Left.swap(_Right);
}
// HASH SUPPORT [variant.hash]
struct _Variant_hash_visitor { // visitation function for hashing variants
template <class _Ty, size_t _Idx>
_NODISCARD size_t operator()(_Tagged<const _Ty&, _Idx> _Obj) const
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 _Variant_raw_visit(_Var.index(), _Var._Storage(), _Variant_hash_visitor{});
}
};
template <>
struct hash<monostate> {
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef monostate _ARGUMENT_TYPE_NAME;
_CXX17_DEPRECATE_ADAPTOR_TYPEDEFS typedef size_t _RESULT_TYPE_NAME;
_NODISCARD size_t operator()(monostate) const noexcept {
return 1729; // Arbitrary value
}
};
_STD_END
#undef _STL_STAMP
#undef _STL_STAMP256
#undef _STL_STAMP64
#undef _STL_STAMP16
#undef _STL_STAMP4
#undef _STL_UNREACHABLE
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif // _HAS_CXX17
#endif // _STL_COMPILER_PREPROCESSOR
#endif // _VARIANT_