// tuple standard header (core) // Copyright (c) Microsoft Corporation. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #ifndef _TUPLE_ #define _TUPLE_ #include #if _STL_COMPILER_PREPROCESSOR #if _HAS_CXX20 #include #endif // _HAS_CXX20 #include <__msvc_iter_core.hpp> #include #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 constexpr bool _Tuple_conditional_explicit_v0 = false; template constexpr bool _Tuple_conditional_explicit_v0, _Srcs...> = !conjunction_v...>; template constexpr bool _Tuple_conditional_explicit_v = _Tuple_conditional_explicit_v0 == sizeof...(_Srcs), _Dest, _Srcs...>; template constexpr bool _Tuple_constructible_v0 = false; template constexpr bool _Tuple_constructible_v0, _Srcs...> = conjunction_v...>; template constexpr bool _Tuple_constructible_v = _Tuple_constructible_v0 == sizeof...(_Srcs), _Dest, _Srcs...>; template struct _Tuple_constructible_val : bool_constant<_Tuple_constructible_v<_Dest, _Srcs...>> {}; template constexpr bool _Tuple_nothrow_constructible_v0 = false; template constexpr bool _Tuple_nothrow_constructible_v0, _Srcs...> = conjunction_v...>; template constexpr bool _Tuple_nothrow_constructible_v = _Tuple_nothrow_constructible_v0 == sizeof...(_Srcs), _Dest, _Srcs...>; template constexpr bool _Tuple_assignable_v0 = false; template constexpr bool _Tuple_assignable_v0, _Srcs...> = conjunction_v...>; // note _Dests& instead of _Dests #if _HAS_CXX23 template constexpr bool _Tuple_assignable_v0, _Srcs...> = conjunction_v...>; #endif // _HAS_CXX23 template constexpr bool _Tuple_assignable_v = _Tuple_assignable_v0 == sizeof...(_Srcs), _Dest, _Srcs...>; template struct _Tuple_assignable_val : bool_constant<_Tuple_assignable_v<_Dest, _Srcs...>> {}; template constexpr bool _Tuple_nothrow_assignable_v0 = false; template constexpr bool _Tuple_nothrow_assignable_v0, _Srcs...> = conjunction_v...>; // note _Dests& instead of _Dests #if _HAS_CXX23 template constexpr bool _Tuple_nothrow_assignable_v0, _Srcs...> = conjunction_v...>; #endif // _HAS_CXX23 template constexpr bool _Tuple_nothrow_assignable_v = _Tuple_nothrow_assignable_v0 == sizeof...(_Srcs), _Dest, _Srcs...>; // Constrain tuple's converting constructors template struct _Tuple_convert_val : true_type {}; template struct _Tuple_convert_val, _OtherTuple, _Uty> : bool_constant, is_constructible<_This, _OtherTuple>, is_convertible<_OtherTuple, _This>>> {}; // Constrain tuple's perfect forwarding constructor (LWG-3121) template struct _Tuple_perfect_val : true_type {}; template struct _Tuple_perfect_val<_Myself, _This2> : bool_constant>> {}; template struct _Tuple_perfect_val, _Uty0, _Uty1> : bool_constant, allocator_arg_t>>, is_same<_Remove_cvref_t<_Ty0>, allocator_arg_t>>> {}; template struct _Tuple_perfect_val, _Uty0, _Uty1, _Uty2> : bool_constant, allocator_arg_t>>, is_same<_Remove_cvref_t<_Ty0>, allocator_arg_t>>> {}; // Note: To improve throughput, this file uses extra _STD qualification for names that appear in the // arguments of enable_if_t. Specifically, we qualify names which appear anywhere in the STL as members of // some class - including injected-class-names! - that we know are not members of the class being defined. // This avoids pointless class-member lookup for those names in this context. template struct _Tuple_val { // stores each value in a tuple constexpr _Tuple_val() : _Val() {} template constexpr _Tuple_val(_Other&& _Arg) : _Val(_STD forward<_Other>(_Arg)) {} template , int> = 0> constexpr _Tuple_val(const _Alloc&, allocator_arg_t, _Other&&... _Arg) : _Val(_STD forward<_Other>(_Arg)...) {} template , _STD is_constructible<_Ty, _STD allocator_arg_t, const _Alloc&, _Other...>>, int> = 0> constexpr _Tuple_val(const _Alloc& _Al, allocator_arg_t, _Other&&... _Arg) : _Val(allocator_arg, _Al, _STD forward<_Other>(_Arg)...) {} template , _STD negation<_STD is_constructible<_Ty, _STD allocator_arg_t, const _Alloc&, _Other...>>>, int> = 0> constexpr _Tuple_val(const _Alloc& _Al, allocator_arg_t, _Other&&... _Arg) : _Val(_STD forward<_Other>(_Arg)..., _Al) {} _Ty _Val; }; struct _Exact_args_t { explicit _Exact_args_t() = default; }; // tag type to disambiguate construction (from one arg per element) struct _Unpack_tuple_t { explicit _Unpack_tuple_t() = default; }; // tag type to disambiguate construction (from unpacking a tuple/pair) struct _Alloc_exact_args_t { explicit _Alloc_exact_args_t() = default; }; // tag type to disambiguate construction (from an allocator and one arg per element) struct _Alloc_unpack_tuple_t { explicit _Alloc_unpack_tuple_t() = default; }; // tag type to disambiguate construction (from an allocator and unpacking a tuple/pair) #if _HAS_CXX23 template >> constexpr bool _Can_construct_values_from_tuple_like_v = false; template constexpr bool _Can_construct_values_from_tuple_like_v, _Other, index_sequence<_Indices...>> = conjunction_v(_STD declval<_Other>()))>...>; #ifdef __EDG__ // TRANSITION, VSO-1900279 template concept _Can_construct_from_tuple_like = _Different_from<_TupleLike, _Tuple> && _Tuple_like_non_subrange<_TupleLike> && (tuple_size_v<_Tuple> == tuple_size_v>) && _Can_construct_values_from_tuple_like_v<_Tuple, _TupleLike> && (tuple_size_v<_Tuple> != 1 || (!is_convertible_v<_TupleLike, tuple_element_t<0, _Tuple>> && !is_constructible_v, _TupleLike>) ); #endif // ^^^ workaround ^^^ template >> struct _Three_way_comparison_result_with_tuple_like {}; template requires #if !defined(__clang__) && !defined(__EDG__) // TRANSITION, DevCom-10265237 (sizeof...(_TTypes) == sizeof...(_Indices)) && #endif // ^^^ workaround ^^^ (requires { typename _Synth_three_way_result<_TTypes, tuple_element_t<_Indices, _UTuple>>; } && ...) struct _Three_way_comparison_result_with_tuple_like, _UTuple, index_sequence<_Indices...>> { using type = common_comparison_category_t<_Synth_three_way_result<_TTypes, tuple_element_t<_Indices, _UTuple>>...>; }; template using _Three_way_comparison_result_with_tuple_like_t = _Three_way_comparison_result_with_tuple_like<_TTuple, _UTuple>::type; template concept _Tuple_like_non_tuple = !_Is_specialization_v<_Ty, tuple> && _Tuple_like<_Ty>; #endif // _HAS_CXX23 template <> class tuple<> { // empty tuple public: constexpr tuple() noexcept = default; /* strengthened */ constexpr tuple(const tuple&) noexcept /* strengthened */ {} // TRANSITION, ABI: should be defaulted #if _HAS_CXX23 template <_Different_from _Other> requires _Tuple_like<_Other> && (tuple_size_v> == 0) constexpr tuple(_Other&&) noexcept /* strengthened */ {} #endif // _HAS_CXX23 template _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc&) noexcept /* strengthened */ {} template _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc&, const tuple&) noexcept /* strengthened */ {} #if _HAS_CXX23 template _Other> requires _Tuple_like<_Other> && (tuple_size_v> == 0) constexpr tuple(allocator_arg_t, const _Alloc&, _Other&&) noexcept /* strengthened */ {} #endif // _HAS_CXX23 template , int> = 0> constexpr tuple(_Tag) noexcept /* strengthened */ {} template , int> = 0> constexpr tuple(_Tag, const _Alloc&) noexcept /* strengthened */ {} constexpr tuple& operator=(const tuple&) = default; #if _HAS_CXX23 constexpr const tuple& operator=(const tuple&) const noexcept /* strengthened */ { return *this; } template <_Different_from _Other> requires _Tuple_like<_Other> && (tuple_size_v> == 0) constexpr tuple& operator=(_Other&&) noexcept /* strengthened */ { return *this; } template <_Different_from _Other> requires _Tuple_like<_Other> && (tuple_size_v> == 0) constexpr const tuple& operator=(_Other&&) const noexcept /* strengthened */ { return *this; } #endif // _HAS_CXX23 _CONSTEXPR20 void swap(tuple&) noexcept {} #if _HAS_CXX23 constexpr void swap(const tuple&) const noexcept {} #endif // _HAS_CXX23 constexpr bool _Equals(const tuple&) const noexcept { return true; } #if _HAS_CXX20 _NODISCARD constexpr strong_ordering _Three_way_compare(const tuple&) const noexcept { return strong_ordering::equal; } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv _NODISCARD constexpr bool _Less(const tuple&) const noexcept { return false; } #endif // ^^^ !_HAS_CXX20 ^^^ #if _HAS_CXX23 template <_Tuple_like_non_tuple _Other> _NODISCARD friend constexpr bool operator==(const tuple&, const _Other&) noexcept /* strengthened */ { static_assert(tuple_size_v<_Other> == 0, "Cannot compare tuples of different sizes (N4950 [tuple.rel]/2)."); return true; } template <_Tuple_like_non_tuple _Other> requires (tuple_size_v> == 0) _NODISCARD friend constexpr strong_ordering operator<=>(const tuple&, const _Other&) noexcept /* strengthened */ { return strong_ordering::equal; } #endif // _HAS_CXX23 }; template class tuple<_This, _Rest...> : private tuple<_Rest...> { // recursive tuple definition public: using _This_type = _This; using _Mybase = tuple<_Rest...>; template , int> = 0> constexpr tuple(_Tag, _This2&& _This_arg, _Rest2&&... _Rest_arg) : _Mybase(_Exact_args_t{}, _STD forward<_Rest2>(_Rest_arg)...), _Myfirst(_STD forward<_This2>(_This_arg)) {} template , int> = 0> constexpr tuple(_Tag, _Tpl&& _Right, index_sequence<_Indices...>); template , int> = 0> constexpr tuple(_Tag, _Tpl&& _Right) : tuple(_Unpack_tuple_t{}, _STD forward<_Tpl>(_Right), make_index_sequence>>{}) {} template , int> = 0> constexpr tuple(_Tag, const _Alloc& _Al, _This2&& _This_arg, _Rest2&&... _Rest_arg) : _Mybase(_Alloc_exact_args_t{}, _Al, _STD forward<_Rest2>(_Rest_arg)...), _Myfirst(_Al, allocator_arg, _STD forward<_This2>(_This_arg)) {} template , int> = 0> constexpr tuple(_Tag, const _Alloc& _Al, _Tpl&& _Right, index_sequence<_Indices...>); template , int> = 0> constexpr tuple(_Tag, const _Alloc& _Al, _Tpl&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD forward<_Tpl>(_Right), make_index_sequence>>{}) {} template , _STD is_default_constructible<_Rest>...>, int> = 0> constexpr explicit( !conjunction_v<_Is_implicitly_default_constructible<_This2>, _Is_implicitly_default_constructible<_Rest>...>) tuple() noexcept(conjunction_v, is_nothrow_default_constructible<_Rest>...>) // strengthened : _Mybase(), _Myfirst() {} template , int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(const _This& _This_arg, const _Rest&... _Rest_arg) noexcept(conjunction_v, is_nothrow_copy_constructible<_Rest>...>) // strengthened : tuple(_Exact_args_t{}, _This_arg, _Rest_arg...) {} template , _STD _Tuple_constructible_val>, int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(_This2&& _This_arg, _Rest2&&... _Rest_arg) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Exact_args_t{}, _STD forward<_This2>(_This_arg), _STD forward<_Rest2>(_Rest_arg)...) {} tuple(const tuple&) = default; tuple(tuple&&) = default; #if _HAS_CXX23 template , _STD _Tuple_convert_val&, _Other...>>, int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(tuple<_Other...>& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _Right) {} #endif // _HAS_CXX23 template , _STD _Tuple_convert_val&, _Other...>>, int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(const tuple<_Other...>& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _Right) {} template , _STD _Tuple_convert_val, _Other...>>, int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(tuple<_Other...>&& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} #if _HAS_CXX23 template , _STD _Tuple_convert_val, _Other...>>, int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(const tuple<_Other...>&& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} template , int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(pair<_First, _Second>& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _Right) {} #endif // _HAS_CXX23 template , int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(const pair<_First, _Second>& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _Right) {} template , int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(pair<_First, _Second>&& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} #if _HAS_CXX23 template , int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(const pair<_First, _Second>&& _Right) noexcept(_Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} template > static constexpr bool _Is_tuple_like_constructor_explicit_v = false; template <_Tuple_like _Other, size_t... _Indices> static constexpr bool _Is_tuple_like_constructor_explicit_v<_Other, index_sequence<_Indices...>> = negation_v(_STD declval<_Other>())), _This>, is_convertible(_STD declval<_Other>())), _Rest>...>>; #ifdef __EDG__ // TRANSITION, VSO-1900279 template , int> = 0> #else // ^^^ workaround / no workaround vvv template <_Different_from _Other> requires _Tuple_like_non_subrange<_Other> && (1 + sizeof...(_Rest) == tuple_size_v>) && _Can_construct_values_from_tuple_like_v && (sizeof...(_Rest) != 0 || (!is_convertible_v<_Other, _This> && !is_constructible_v<_This, _Other>) ) #endif // ^^^ no workaround ^^^ constexpr explicit(_Is_tuple_like_constructor_explicit_v<_Other>) tuple(_Other&& _Right) : tuple(_Unpack_tuple_t{}, _STD forward<_Other>(_Right)) { } #endif // _HAS_CXX23 template , _STD is_default_constructible<_Rest>...>, int> = 0> _CONSTEXPR20 explicit( !conjunction_v<_Is_implicitly_default_constructible<_This2>, _Is_implicitly_default_constructible<_Rest>...>) tuple(allocator_arg_t, const _Alloc& _Al) : _Mybase(allocator_arg, _Al), _Myfirst(_Al, allocator_arg) {} template , int> = 0> _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, const _This& _This_arg, const _Rest&... _Rest_arg) : tuple(_Alloc_exact_args_t{}, _Al, _This_arg, _Rest_arg...) {} template , _STD _Tuple_constructible_val>, int> = 0> _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, _This2&& _This_arg, _Rest2&&... _Rest_arg) : tuple(_Alloc_exact_args_t{}, _Al, _STD forward<_This2>(_This_arg), _STD forward<_Rest2>(_Rest_arg)...) {} template , int> = 0> _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc& _Al, const tuple& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} template , int> = 0> _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc& _Al, tuple&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} #if _HAS_CXX23 template , _STD _Tuple_convert_val&, _Other...>>, int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, tuple<_Other...>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} #endif // _HAS_CXX23 template , _STD _Tuple_convert_val&, _Other...>>, int> = 0> _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, const tuple<_Other...>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} template , _STD _Tuple_convert_val, _Other...>>, int> = 0> _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, tuple<_Other...>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} #if _HAS_CXX23 template , _STD _Tuple_convert_val, _Other...>>, int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, const tuple<_Other...>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} template , int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, pair<_First, _Second>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} #endif // _HAS_CXX23 template , int> = 0> _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, const pair<_First, _Second>& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _Right) {} template , int> = 0> _CONSTEXPR20 explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, pair<_First, _Second>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} #if _HAS_CXX23 template , int> = 0> constexpr explicit(_Tuple_conditional_explicit_v) tuple(allocator_arg_t, const _Alloc& _Al, const pair<_First, _Second>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} #ifdef __EDG__ // TRANSITION, VSO-1900279 template , int> = 0> #else // ^^^ workaround / no workaround vvv template _Other> requires _Tuple_like_non_subrange<_Other> && (1 + sizeof...(_Rest) == tuple_size_v>) && _Can_construct_values_from_tuple_like_v && (sizeof...(_Rest) != 0 || (!is_convertible_v<_Other, _This> && !is_constructible_v<_This, _Other>) ) #endif // ^^^ no workaround ^^^ constexpr explicit(_Is_tuple_like_constructor_explicit_v<_Other>) tuple(allocator_arg_t, const _Alloc& _Al, _Other&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD forward<_Other>(_Right)) { } #endif // _HAS_CXX23 tuple& operator=(const volatile tuple&) = delete; template , _STD _Is_copy_assignable_no_precondition_check<_Rest>...>, int> = 0> _CONSTEXPR20 tuple& operator=(_Identity_t _Right) noexcept( conjunction_v, is_nothrow_copy_assignable<_Rest>...>) /* strengthened */ { _Myfirst._Val = _Right._Myfirst._Val; _Get_rest() = _Right._Get_rest(); return *this; } #if _HAS_CXX23 template requires conjunction_v<_STD _Is_copy_assignable_no_precondition_check, _STD _Is_copy_assignable_no_precondition_check...> constexpr const tuple& operator=(_Identity_t _Right) const noexcept(conjunction_v, is_nothrow_copy_assignable...>) /* strengthened */ { _Myfirst._Val = _Right._Myfirst._Val; _Get_rest() = _Right._Get_rest(); return *this; } #endif // _HAS_CXX23 template , _STD _Is_move_assignable_no_precondition_check<_Rest>...>, int> = 0> _CONSTEXPR20 tuple& operator=(_Identity_t<_Myself&&> _Right) noexcept(conjunction_v, is_nothrow_move_assignable<_Rest>...>) { _Myfirst._Val = _STD forward<_This>(_Right._Myfirst._Val); _Get_rest() = _STD forward<_Mybase>(_Right._Get_rest()); return *this; } #if _HAS_CXX23 template requires conjunction_v<_STD _Is_assignable_no_precondition_check, _STD _Is_assignable_no_precondition_check...> constexpr const tuple& operator=(_Identity_t<_Myself&&> _Right) const noexcept(conjunction_v, is_nothrow_assignable...>) /* strengthened */ { _Myfirst._Val = _STD forward<_This>(_Right._Myfirst._Val); _Get_rest() = _STD forward<_Mybase>(_Right._Get_rest()); return *this; } #endif // _HAS_CXX23 template >>, _STD _Tuple_assignable_val>, int> = 0> _CONSTEXPR20 tuple& operator=(const tuple<_Other...>& _Right) noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _Right._Myfirst._Val; _Get_rest() = _Right._Get_rest(); return *this; } #if _HAS_CXX23 template requires (!is_same_v>) && _Tuple_assignable_v constexpr const tuple& operator=(const tuple<_Other...>& _Right) const noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _Right._Myfirst._Val; _Get_rest() = _Right._Get_rest(); return *this; } #endif // _HAS_CXX23 template >>, _STD _Tuple_assignable_val>, int> = 0> _CONSTEXPR20 tuple& operator=(tuple<_Other...>&& _Right) noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _STD forward::_This_type>(_Right._Myfirst._Val); _Get_rest() = _STD forward::_Mybase>(_Right._Get_rest()); return *this; } #if _HAS_CXX23 template requires (!is_same_v>) && _Tuple_assignable_v constexpr const tuple& operator=(tuple<_Other...>&& _Right) const noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _STD forward::_This_type>(_Right._Myfirst._Val); _Get_rest() = _STD forward::_Mybase>(_Right._Get_rest()); return *this; } #endif // _HAS_CXX23 template , int> = 0> _CONSTEXPR20 tuple& operator=(const pair<_First, _Second>& _Right) noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _Right.first; _Get_rest()._Myfirst._Val = _Right.second; return *this; } #if _HAS_CXX23 template requires _Tuple_assignable_v constexpr const tuple& operator=(const pair<_First, _Second>& _Right) const noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _Right.first; _Get_rest()._Myfirst._Val = _Right.second; return *this; } #endif // _HAS_CXX23 template , int> = 0> _CONSTEXPR20 tuple& operator=(pair<_First, _Second>&& _Right) noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _STD forward<_First>(_Right.first); _Get_rest()._Myfirst._Val = _STD forward<_Second>(_Right.second); return *this; } #if _HAS_CXX23 template requires _Tuple_assignable_v constexpr const tuple& operator=(pair<_First, _Second>&& _Right) const noexcept(_Tuple_nothrow_assignable_v) /* strengthened */ { _Myfirst._Val = _STD forward<_First>(_Right.first); _Get_rest()._Myfirst._Val = _STD forward<_Second>(_Right.second); return *this; } template > static constexpr bool _Can_assign_values_from_tuple_like_v = false; template <_Tuple_like _Other, size_t... _Indices> static constexpr bool _Can_assign_values_from_tuple_like_v> = conjunction_v(_STD declval<_Other>()))>, is_assignable<_Rest&, decltype(_STD get<_Indices + 1>(_STD declval<_Other>()))>...>; template <_Tuple_like _Other, size_t... _Indices> static constexpr bool _Can_assign_values_from_tuple_like_v> = conjunction_v(_STD declval<_Other>()))>, is_assignable(_STD declval<_Other>()))>...>; template <_Tuple_like _Other, size_t... _Indices> constexpr void _Assign_tuple_like(_Other&& _Right, index_sequence<_Indices...>) { ((void) (_STD get<_Indices>(*this) = _STD get<_Indices>(_STD forward<_Other>(_Right))), ...); } template <_Tuple_like _Other, size_t... _Indices> constexpr void _Assign_tuple_like(_Other&& _Right, index_sequence<_Indices...>) const { ((void) (_STD get<_Indices>(*this) = _STD get<_Indices>(_STD forward<_Other>(_Right))), ...); } template <_Different_from _Other> requires _Tuple_like_non_subrange<_Other> && (1 + sizeof...(_Rest) == tuple_size_v>) && _Can_assign_values_from_tuple_like_v constexpr tuple& operator=(_Other&& _Right) { _Assign_tuple_like(_STD forward<_Other>(_Right), make_index_sequence<1 + sizeof...(_Rest)>{}); return *this; } template <_Different_from _Other> requires _Tuple_like_non_subrange<_Other> && (1 + sizeof...(_Rest) == tuple_size_v>) && _Can_assign_values_from_tuple_like_v constexpr const tuple& operator=(_Other&& _Right) const { _Assign_tuple_like(_STD forward<_Other>(_Right), make_index_sequence<1 + sizeof...(_Rest)>{}); return *this; } #endif // _HAS_CXX23 _CONSTEXPR20 void swap(tuple& _Right) noexcept(conjunction_v<_Is_nothrow_swappable<_This>, _Is_nothrow_swappable<_Rest>...>) { using _STD swap; swap(_Myfirst._Val, _Right._Myfirst._Val); // intentional ADL _Mybase::swap(_Right._Get_rest()); } #if _HAS_CXX23 template // see GH-3013 constexpr void swap(const tuple& _Right) const noexcept(conjunction_v, is_nothrow_swappable...>) { using _STD swap; swap(_Myfirst._Val, _Right._Myfirst._Val); // intentional ADL _Mybase::swap(_Right._Get_rest()); } #endif // _HAS_CXX23 constexpr _Mybase& _Get_rest() noexcept { // get reference to rest of elements return *this; } constexpr const _Mybase& _Get_rest() const noexcept { // get const reference to rest of elements return *this; } template constexpr bool _Equals(const tuple<_Other...>& _Right) const { return _Myfirst._Val == _Right._Myfirst._Val && _Mybase::_Equals(_Right._Get_rest()); } #if _HAS_CXX20 template _NODISCARD constexpr common_comparison_category_t<_Synth_three_way_result<_This, _First>, _Synth_three_way_result<_Rest, _Other>...> _Three_way_compare(const tuple<_First, _Other...>& _Right) const { if (auto _Result = _Synth_three_way{}(_Myfirst._Val, _Right._Myfirst._Val); _Result != 0) { return _Result; } return _Mybase::_Three_way_compare(_Right._Get_rest()); } #if _HAS_CXX23 template > static constexpr bool _Can_equal_compare_with_tuple_like_v = false; template static constexpr bool _Can_equal_compare_with_tuple_like_v<_Other, index_sequence<_Indices...>> = (requires(const tuple& _Left, const _Other& _Right) { { _STD get<_Indices>(_Left) == _STD get<_Indices>(_Right) } -> _Boolean_testable; } && ...); template _NODISCARD constexpr bool _Equals_to_tuple_like(const _Other& _Right, index_sequence<_Indices...>) const { return ((_STD get<_Indices>(*this) == _STD get<_Indices>(_Right)) && ...); } template <_Tuple_like_non_tuple _Other> _NODISCARD friend constexpr bool operator==(const tuple& _Left, const _Other& _Right) { static_assert(1 + sizeof...(_Rest) == tuple_size_v<_Other>, "Cannot compare tuples of different sizes (N4950 [tuple.rel]/2)."); static_assert(_Can_equal_compare_with_tuple_like_v<_Other>, "For all i, where 0 <= i < sizeof...(TTypes), get(t) == get(u) must be a valid expression (N4950 " "[tuple.rel]/2)."); return _Left._Equals_to_tuple_like(_Right, make_index_sequence<1 + sizeof...(_Rest)>{}); } template _NODISCARD constexpr auto _Three_way_compare_with_tuple_like( const _Other& _Right, index_sequence<_Indices...>) const { _Three_way_comparison_result_with_tuple_like_t _Result = strong_ordering::equal; (void) (((_Result = _Synth_three_way{}(_STD get<_Indices>(*this), _STD get<_Indices>(_Right))) == 0) && ...); return _Result; } template <_Tuple_like_non_tuple _Other> _NODISCARD friend constexpr auto operator<=>(const tuple& _Left, const _Other& _Right) // -> _Three_way_comparison_result_with_tuple_like_t { return _Left._Three_way_compare_with_tuple_like(_Right, make_index_sequence<1 + sizeof...(_Rest)>{}); } #endif // _HAS_CXX23 #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template _NODISCARD constexpr bool _Less(const tuple<_Other...>& _Right) const { return _Myfirst._Val < _Right._Myfirst._Val || (!(_Right._Myfirst._Val < _Myfirst._Val) && _Mybase::_Less(_Right._Get_rest())); } #endif // ^^^ !_HAS_CXX20 ^^^ template friend constexpr tuple_element_t<_Index, tuple<_Types...>>& get(tuple<_Types...>& _Tuple) noexcept; template friend constexpr const tuple_element_t<_Index, tuple<_Types...>>& get(const tuple<_Types...>& _Tuple) noexcept; template friend constexpr tuple_element_t<_Index, tuple<_Types...>>&& get(tuple<_Types...>&& _Tuple) noexcept; template friend constexpr const tuple_element_t<_Index, tuple<_Types...>>&& get(const tuple<_Types...>&& _Tuple) noexcept; template friend constexpr auto&& _Tuple_get(tuple<_Types...>&& _Tuple) noexcept; template friend constexpr _Ty& get(tuple<_Types...>& _Tuple) noexcept; template friend constexpr const _Ty& get(const tuple<_Types...>& _Tuple) noexcept; template friend constexpr _Ty&& get(tuple<_Types...>&& _Tuple) noexcept; template friend constexpr const _Ty&& get(const tuple<_Types...>&& _Tuple) noexcept; _Tuple_val<_This> _Myfirst; // the stored element }; #if _HAS_CXX17 template tuple(_Types...) -> tuple<_Types...>; template tuple(pair<_Ty1, _Ty2>) -> tuple<_Ty1, _Ty2>; template tuple(allocator_arg_t, _Alloc, _Types...) -> tuple<_Types...>; template tuple(allocator_arg_t, _Alloc, pair<_Ty1, _Ty2>) -> tuple<_Ty1, _Ty2>; template tuple(allocator_arg_t, _Alloc, tuple<_Types...>) -> tuple<_Types...>; #endif // _HAS_CXX17 _EXPORT_STD template _NODISCARD constexpr bool operator==(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { static_assert( sizeof...(_Types1) == sizeof...(_Types2), "Cannot compare tuples of different sizes (N4950 [tuple.rel]/2)."); return _Left._Equals(_Right); } #if _HAS_CXX20 _EXPORT_STD template _NODISCARD constexpr common_comparison_category_t<_Synth_three_way_result<_Types1, _Types2>...> operator<=>( const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { return _Left._Three_way_compare(_Right); } #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template _NODISCARD constexpr bool operator!=(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { return !(_Left == _Right); } template _NODISCARD constexpr bool operator<(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { static_assert(sizeof...(_Types1) == sizeof...(_Types2), "cannot compare tuples of different sizes"); return _Left._Less(_Right); } template _NODISCARD constexpr bool operator>=(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { return !(_Left < _Right); } template _NODISCARD constexpr bool operator>(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { return _Right < _Left; } template _NODISCARD constexpr bool operator<=(const tuple<_Types1...>& _Left, const tuple<_Types2...>& _Right) { return !(_Right < _Left); } #endif // ^^^ !_HAS_CXX20 ^^^ _EXPORT_STD template ...>, int> = 0> _CONSTEXPR20 void swap(tuple<_Types...>& _Left, tuple<_Types...>& _Right) noexcept(noexcept(_Left.swap(_Right))) { _Left.swap(_Right); } #if _HAS_CXX23 _EXPORT_STD template requires conjunction_v...> constexpr void swap(const tuple<_Types...>& _Left, const tuple<_Types...>& _Right) noexcept(noexcept(_Left.swap(_Right))) { _Left.swap(_Right); } #endif // _HAS_CXX23 _EXPORT_STD template _NODISCARD constexpr tuple_element_t<_Index, tuple<_Types...>>& get(tuple<_Types...>& _Tuple) noexcept { using _Ttype = typename tuple_element<_Index, tuple<_Types...>>::_Ttype; return static_cast<_Ttype&>(_Tuple)._Myfirst._Val; } _EXPORT_STD template _NODISCARD constexpr const tuple_element_t<_Index, tuple<_Types...>>& get(const tuple<_Types...>& _Tuple) noexcept { using _Ttype = typename tuple_element<_Index, tuple<_Types...>>::_Ttype; return static_cast(_Tuple)._Myfirst._Val; } _EXPORT_STD template _NODISCARD constexpr tuple_element_t<_Index, tuple<_Types...>>&& get(tuple<_Types...>&& _Tuple) noexcept { using _Ty = tuple_element_t<_Index, tuple<_Types...>>; using _Ttype = typename tuple_element<_Index, tuple<_Types...>>::_Ttype; return static_cast<_Ty&&>(static_cast<_Ttype&>(_Tuple)._Myfirst._Val); } _EXPORT_STD template _NODISCARD constexpr const tuple_element_t<_Index, tuple<_Types...>>&& get(const tuple<_Types...>&& _Tuple) noexcept { using _Ty = tuple_element_t<_Index, tuple<_Types...>>; using _Ttype = typename tuple_element<_Index, tuple<_Types...>>::_Ttype; return static_cast(static_cast(_Tuple)._Myfirst._Val); } template _NODISCARD constexpr auto&& _Tuple_get(tuple<_Types...>&& _Tuple) noexcept { // used by pair's piecewise constructor using _Ty = tuple_element_t<_Index, tuple<_Types...>>; using _Ttype = typename tuple_element<_Index, tuple<_Types...>>::_Ttype; return static_cast<_Ty&&>(static_cast<_Ttype&>(_Tuple)._Myfirst._Val); } _EXPORT_STD template _NODISCARD constexpr _Ty& get(tuple<_Types...>& _Tuple) noexcept { constexpr size_t _Idx = _Meta_find_unique_index, _Ty>::value; if constexpr (_Idx < sizeof...(_Types)) { using _Ttype = typename tuple_element<_Idx, tuple<_Types...>>::_Ttype; return static_cast<_Ttype&>(_Tuple)._Myfirst._Val; } else { static_assert(false, "get(tuple&) " "requires T to occur exactly once in Types. (N4971 [tuple.elem]/5)"); } } _EXPORT_STD template _NODISCARD constexpr const _Ty& get(const tuple<_Types...>& _Tuple) noexcept { constexpr size_t _Idx = _Meta_find_unique_index, _Ty>::value; if constexpr (_Idx < sizeof...(_Types)) { using _Ttype = typename tuple_element<_Idx, tuple<_Types...>>::_Ttype; return static_cast(_Tuple)._Myfirst._Val; } else { static_assert(false, "get(const tuple&) " "requires T to occur exactly once in Types. (N4971 [tuple.elem]/5)"); } } _EXPORT_STD template _NODISCARD constexpr _Ty&& get(tuple<_Types...>&& _Tuple) noexcept { constexpr size_t _Idx = _Meta_find_unique_index, _Ty>::value; if constexpr (_Idx < sizeof...(_Types)) { using _Ttype = typename tuple_element<_Idx, tuple<_Types...>>::_Ttype; return static_cast<_Ty&&>(static_cast<_Ttype&>(_Tuple)._Myfirst._Val); } else { static_assert(false, "get(tuple&&) " "requires T to occur exactly once in Types. (N4971 [tuple.elem]/5)"); } } _EXPORT_STD template _NODISCARD constexpr const _Ty&& get(const tuple<_Types...>&& _Tuple) noexcept { constexpr size_t _Idx = _Meta_find_unique_index, _Ty>::value; if constexpr (_Idx < sizeof...(_Types)) { using _Ttype = typename tuple_element<_Idx, tuple<_Types...>>::_Ttype; return static_cast(static_cast(_Tuple)._Myfirst._Val); } else { static_assert(false, "get(const tuple&&) " "requires T to occur exactly once in Types. (N4971 [tuple.elem]/5)"); } } template template , int> /* = 0 */> constexpr tuple<_This, _Rest...>::tuple(_Tag, _Tpl&& _Right, index_sequence<_Indices...>) : tuple(_Exact_args_t{}, _STD get<_Indices>(_STD forward<_Tpl>(_Right))...) {} template template , int> /* = 0 */> constexpr tuple<_This, _Rest...>::tuple(_Tag, const _Alloc& _Al, _Tpl&& _Right, index_sequence<_Indices...>) : tuple(_Alloc_exact_args_t{}, _Al, _STD get<_Indices>(_STD forward<_Tpl>(_Right))...) {} _EXPORT_STD template _NODISCARD constexpr tuple<_Unrefwrap_t<_Types>...> make_tuple(_Types&&... _Args) { // make tuple from elements using _Ttype = tuple<_Unrefwrap_t<_Types>...>; return _Ttype(_STD forward<_Types>(_Args)...); } _EXPORT_STD template _NODISCARD constexpr tuple<_Types&...> tie(_Types&... _Args) noexcept { // make tuple from elements using _Ttype = tuple<_Types&...>; return _Ttype(_Args...); } _EXPORT_STD template _NODISCARD constexpr tuple<_Types&&...> forward_as_tuple(_Types&&... _Args) noexcept { // forward arguments in a tuple return tuple<_Types&&...>(_STD forward<_Types>(_Args)...); } template struct _Tuple_cat2; template struct _Tuple_cat2<_Ty, index_sequence<_Kx...>, index_sequence<_Ix...>, _Ix_next> { using _Ret = tuple>>...>; using _Kx_seq = index_sequence<_Kx...>; using _Ix_seq = index_sequence<_Ix...>; }; template struct _Tuple_cat2<_Ty, index_sequence<_Kx...>, index_sequence<_Ix...>, _Ix_next, index_sequence<_Kx_next...>, _Rest...> : _Tuple_cat2<_Ty, index_sequence<_Kx..., _Kx_next...>, index_sequence<_Ix..., (_Ix_next + 0 * _Kx_next)...>, // repeat _Ix_next, ignoring the elements of _Kx_next _Ix_next + 1, _Rest...> {}; #if _HAS_CXX23 template <_Tuple_like... _Tuples> #else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv template #endif // ^^^ !_HAS_CXX23 ^^^ using _Tuple_cat1 = _Tuple_cat2, index_sequence<>, index_sequence<>, 0, make_index_sequence>>...>; template constexpr _Ret _Tuple_cat(index_sequence<_Kx...>, index_sequence<_Ix...>, _Ty _Arg) { return _Ret{_STD get<_Kx>(_STD get<_Ix>(_STD move(_Arg)))...}; } #if _HAS_CXX23 _EXPORT_STD template <_Tuple_like... _Tuples> #else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv _EXPORT_STD template #endif // ^^^ !_HAS_CXX23 ^^^ _NODISCARD constexpr typename _Tuple_cat1<_Tuples...>::_Ret tuple_cat(_Tuples&&... _Tpls) { // concatenate tuples using _Cat1 = _Tuple_cat1<_Tuples...>; using _Ret = typename _Cat1::_Ret; using _Kx_seq = typename _Cat1::_Kx_seq; using _Ix_seq = typename _Cat1::_Ix_seq; return _STD _Tuple_cat<_Ret>(_Kx_seq{}, _Ix_seq{}, _STD forward_as_tuple(_STD forward<_Tuples>(_Tpls)...)); } #if _HAS_CXX17 #if _HAS_CXX23 template #else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv template #endif // ^^^ !_HAS_CXX23 ^^^ constexpr decltype(auto) _Apply_impl(_Callable&& _Obj, _Tuple&& _Tpl, index_sequence<_Indices...>) noexcept(noexcept(_STD invoke(_STD forward<_Callable>(_Obj), _STD get<_Indices>(_STD forward<_Tuple>(_Tpl))...))) { return _STD invoke(_STD forward<_Callable>(_Obj), _STD get<_Indices>(_STD forward<_Tuple>(_Tpl))...); } #if _HAS_CXX23 _EXPORT_STD template #else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv _EXPORT_STD template #endif // ^^^ !_HAS_CXX23 ^^^ constexpr decltype(auto) apply(_Callable&& _Obj, _Tuple&& _Tpl) noexcept(noexcept(_STD _Apply_impl(_STD forward<_Callable>(_Obj), _STD forward<_Tuple>(_Tpl), make_index_sequence>>{}))) { return _STD _Apply_impl(_STD forward<_Callable>(_Obj), _STD forward<_Tuple>(_Tpl), make_index_sequence>>{}); } template >>> constexpr bool _Can_make_from_tuple = false; template constexpr bool _Can_make_from_tuple<_Ty, _Tuple, index_sequence<_Indices...>> = is_constructible_v<_Ty, decltype(_STD get<_Indices>(_STD declval<_Tuple>()))...>; template constexpr _Ty _Make_from_tuple_impl(_Tuple&& _Tpl, index_sequence<_Indices...>) noexcept(is_nothrow_constructible_v<_Ty, decltype(_STD get<_Indices>(_STD forward<_Tuple>(_Tpl)))...>) { return _Ty(_STD get<_Indices>(_STD forward<_Tuple>(_Tpl))...); } #if _HAS_CXX23 _EXPORT_STD template requires _Can_make_from_tuple<_Ty, _Tuple> #elif _HAS_CXX20 _EXPORT_STD template requires _Can_make_from_tuple<_Ty, _Tuple> #else // ^^^ _HAS_CXX20 / !_HAS_CXX20 vvv template , int> = 0> #endif // ^^^ !_HAS_CXX20 ^^^ _NODISCARD constexpr _Ty make_from_tuple(_Tuple&& _Tpl) noexcept(noexcept(_STD _Make_from_tuple_impl<_Ty>( _STD forward<_Tuple>(_Tpl), make_index_sequence>>{}))) /* strengthened */ { // construct _Ty from the elements of _Tpl return _STD _Make_from_tuple_impl<_Ty>( _STD forward<_Tuple>(_Tpl), make_index_sequence>>{}); } #endif // _HAS_CXX17 template struct uses_allocator, _Alloc> : true_type {}; // true_type if container allocator enabled #if _HAS_CXX23 template <_Tuple_like _TTuple, _Tuple_like _UTuple, template class _TQual, template class _UQual, class _Indices = make_index_sequence>> struct _Tuple_like_common_reference; template class _TQual, template class _UQual, size_t... _Indices> requires requires { typename tuple>, _UQual>>...>; } struct _Tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual, index_sequence<_Indices...>> { using type = tuple< common_reference_t<_TQual>, _UQual>>...>; }; template <_Tuple_like _TTuple, _Tuple_like _UTuple, template class _TQual, template class _UQual> requires (_Is_specialization_v<_TTuple, tuple> || _Is_specialization_v<_UTuple, tuple>) && is_same_v<_TTuple, decay_t<_TTuple>> && is_same_v<_UTuple, decay_t<_UTuple>> && (tuple_size_v<_TTuple> == tuple_size_v<_UTuple>) && requires { typename _Tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual>::type; } struct basic_common_reference<_TTuple, _UTuple, _TQual, _UQual> { using type = _Tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual>::type; }; template <_Tuple_like _TTuple, _Tuple_like _UTuple, class _Indices = make_index_sequence>> struct _Tuple_like_common_type; template requires requires { typename tuple, tuple_element_t<_Indices, _UTuple>>...>; } struct _Tuple_like_common_type<_TTuple, _UTuple, index_sequence<_Indices...>> { using type = tuple, tuple_element_t<_Indices, _UTuple>>...>; }; template <_Tuple_like _TTuple, _Tuple_like _UTuple> requires (_Is_specialization_v<_TTuple, tuple> || _Is_specialization_v<_UTuple, tuple>) && is_same_v<_TTuple, decay_t<_TTuple>> && is_same_v<_UTuple, decay_t<_UTuple>> && (tuple_size_v<_TTuple> == tuple_size_v<_UTuple>) && requires { typename _Tuple_like_common_type<_TTuple, _UTuple>::type; } struct common_type<_TTuple, _UTuple> { using type = _Tuple_like_common_type<_TTuple, _UTuple>::type; }; #endif // _HAS_CXX23 #if _HAS_TR1_NAMESPACE namespace _DEPRECATE_TR1_NAMESPACE tr1 { using _STD get; using _STD ignore; using _STD make_tuple; using _STD ref; using _STD tie; using _STD tuple; } // namespace _DEPRECATE_TR1_NAMESPACE tr1 #endif // _HAS_TR1_NAMESPACE _STD_END #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) #pragma pack(pop) #endif // _STL_COMPILER_PREPROCESSOR #endif // _TUPLE_