diff options
author | Hui Xie <hui.xie1990@gmail.com> | 2022-05-12 13:23:11 +0100 |
---|---|---|
committer | Hui Xie <hui.xie1990@gmail.com> | 2022-06-23 21:28:57 +0100 |
commit | 95733a55b986e73f4d8f5314e0d4557d8ae0b226 (patch) | |
tree | ab08243627cbcca1b0e91b1ffa3cd706d7e21229 /libcxx/include/tuple | |
parent | 23d6cde14de352e05c66ae34cd237e3a7a8955d1 (diff) | |
download | llvm-95733a55b986e73f4d8f5314e0d4557d8ae0b226.zip llvm-95733a55b986e73f4d8f5314e0d4557d8ae0b226.tar.gz llvm-95733a55b986e73f4d8f5314e0d4557d8ae0b226.tar.bz2 |
[libc++] P2321R2 section [tuple.tuple]. Adding C++23 constructors, assignment operators and swaps to `tuple`
1. for constructors that takes cvref variation of tuple<UTypes...>, there
used to be two SFINAE helper _EnableCopyFromOtherTuple,
_EnableMoveFromOtherTuple. And the implementations of these two helpers
seem to slightly differ from the spec. But now, we need 4 variations.
Instead of adding another two, this change refactored it to a single one
_EnableCtrFromUTypesTuple, which directly maps to the spec without
changing the C++11 behaviour. However, we need the helper __copy_cvref_t
to get the type of std::get<i>(cvref tuple<Utypes...>) for different
cvref, so I made __copy_cvref_t to be available in C++11.
2. for constructors that takes variations of std::pair, there used to be
four helpers _EnableExplicitCopyFromPair, _EnableImplicitCopyFromPair,
_EnableImplicitMoveFromPair, _EnableExplicitMoveFromPair. Instead of
adding another four, this change refactored into two helper
_EnableCtrFromPair and _BothImplicitlyConvertible. This also removes the
need to use _nat
3. for const member assignment operator, since the requirement is very
simple, I haven't refactored the old code but instead directly adding
the new c++23 code.
4. for const swap, I pretty much copy pasted the non-const version to make
these overloads look consistent
5. while doing these change, I found two of the old constructors wasn't
marked constexpr for C++20 but they should. fixed them and added unit
tests
Reviewed By: #libc, ldionne
Differential Revision: https://reviews.llvm.org/D116621
Diffstat (limited to 'libcxx/include/tuple')
-rw-r--r-- | libcxx/include/tuple | 431 |
1 files changed, 310 insertions, 121 deletions
diff --git a/libcxx/include/tuple b/libcxx/include/tuple index 251b685..d0c1592 100644 --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -25,14 +25,24 @@ public: explicit(see-below) tuple(U&&...); // constexpr in C++14 tuple(const tuple&) = default; tuple(tuple&&) = default; + + template<class... UTypes> + constexpr explicit(see-below) tuple(tuple<UTypes...>&); // C++23 template <class... U> explicit(see-below) tuple(const tuple<U...>&); // constexpr in C++14 template <class... U> explicit(see-below) tuple(tuple<U...>&&); // constexpr in C++14 + template<class... UTypes> + constexpr explicit(see-below) tuple(const tuple<UTypes...>&&); // C++23 + + template<class U1, class U2> + constexpr explicit(see-below) tuple(pair<U1, U2>&); // iff sizeof...(Types) == 2 // C++23 template <class U1, class U2> explicit(see-below) tuple(const pair<U1, U2>&); // iff sizeof...(T) == 2 // constexpr in C++14 template <class U1, class U2> explicit(see-below) tuple(pair<U1, U2>&&); // iff sizeof...(T) == 2 // constexpr in C++14 + template<class U1, class U2> + constexpr explicit(see-below) tuple(const pair<U1, U2>&&); // iff sizeof...(Types) == 2 // C++23 // allocator-extended constructors template <class Alloc> @@ -45,25 +55,47 @@ public: tuple(allocator_arg_t, const Alloc& a, const tuple&); // constexpr in C++20 template <class Alloc> tuple(allocator_arg_t, const Alloc& a, tuple&&); // constexpr in C++20 + template<class Alloc, class... UTypes> + constexpr explicit(see-below) + tuple(allocator_arg_t, const Alloc& a, tuple<UTypes...>&); // C++23 template <class Alloc, class... U> explicit(see-below) tuple(allocator_arg_t, const Alloc& a, const tuple<U...>&); // constexpr in C++20 template <class Alloc, class... U> explicit(see-below) tuple(allocator_arg_t, const Alloc& a, tuple<U...>&&); // constexpr in C++20 + template<class Alloc, class... UTypes> + constexpr explicit(see-below) + tuple(allocator_arg_t, const Alloc& a, const tuple<UTypes...>&&); // C++23 + template<class Alloc, class U1, class U2> + constexpr explicit(see-below) + tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&); // C++23 template <class Alloc, class U1, class U2> explicit(see-below) tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&); // constexpr in C++20 template <class Alloc, class U1, class U2> explicit(see-below) tuple(allocator_arg_t, const Alloc& a, pair<U1, U2>&&); // constexpr in C++20 + template<class Alloc, class U1, class U2> + constexpr explicit(see-below) + tuple(allocator_arg_t, const Alloc& a, const pair<U1, U2>&&); // C++23 tuple& operator=(const tuple&); // constexpr in C++20 + constexpr const tuple& operator=(const tuple&) const; // C++23 tuple& operator=(tuple&&) noexcept(is_nothrow_move_assignable_v<T> && ...); // constexpr in C++20 + constexpr const tuple& operator=(tuple&&) const; // C++23 template <class... U> tuple& operator=(const tuple<U...>&); // constexpr in C++20 + template<class... UTypes> + constexpr const tuple& operator=(const tuple<UTypes...>&) const; // C++23 template <class... U> tuple& operator=(tuple<U...>&&); // constexpr in C++20 + template<class... UTypes> + constexpr const tuple& operator=(tuple<UTypes...>&&) const; // C++23 template <class U1, class U2> tuple& operator=(const pair<U1, U2>&); // iff sizeof...(T) == 2 // constexpr in C++20 + template<class U1, class U2> + constexpr const tuple& operator=(const pair<U1, U2>&) const; // iff sizeof...(Types) == 2 // C++23 template <class U1, class U2> tuple& operator=(pair<U1, U2>&&); // iff sizeof...(T) == 2 // constexpr in C++20 + template<class U1, class U2> + constexpr const tuple& operator=(pair<U1, U2>&&) const; // iff sizeof...(Types) == 2 // C++23 template<class U, size_t N> tuple& operator=(array<U, N> const&) // iff sizeof...(T) == N, EXTENSION @@ -71,6 +103,7 @@ public: tuple& operator=(array<U, N>&&) // iff sizeof...(T) == N, EXTENSION void swap(tuple&) noexcept(AND(swap(declval<T&>(), declval<T&>())...)); // constexpr in C++20 + constexpr void swap(const tuple&) const noexcept(see-below); // C++23 }; @@ -161,6 +194,9 @@ template <class... Types> void swap(tuple<Types...>& x, tuple<Types...>& y) noexcept(noexcept(x.swap(y))); +template <class... Types> + constexpr void swap(const tuple<Types...>& x, const tuple<Types...>& y) noexcept(see-below); // C++23 + } // std */ @@ -210,6 +246,13 @@ void swap(__tuple_leaf<_Ip, _Hp, _Ep>& __x, __tuple_leaf<_Ip, _Hp, _Ep>& __y) swap(__x.get(), __y.get()); } +template <size_t _Ip, class _Hp, bool _Ep> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 +void swap(const __tuple_leaf<_Ip, _Hp, _Ep>& __x, const __tuple_leaf<_Ip, _Hp, _Ep>& __y) + _NOEXCEPT_(__is_nothrow_swappable<const _Hp>::value) { + swap(__x.get(), __y.get()); +} + template <size_t _Ip, class _Hp, bool> class __tuple_leaf { @@ -298,6 +341,12 @@ public: return 0; } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + int swap(const __tuple_leaf& __t) const _NOEXCEPT_(__is_nothrow_swappable<const __tuple_leaf>::value) { + _VSTD::swap(*this, __t); + return 0; + } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 _Hp& get() _NOEXCEPT {return __value_;} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const _Hp& get() const _NOEXCEPT {return __value_;} }; @@ -364,6 +413,12 @@ public: return 0; } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + int swap(const __tuple_leaf& __rhs) const _NOEXCEPT_(__is_nothrow_swappable<const __tuple_leaf>::value) { + _VSTD::swap(*this, __rhs); + return 0; + } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 _Hp& get() _NOEXCEPT {return static_cast<_Hp&>(*this);} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 const _Hp& get() const _NOEXCEPT {return static_cast<const _Hp&>(*this);} }; @@ -454,6 +509,13 @@ struct _LIBCPP_DECLSPEC_EMPTY_BASES __tuple_impl<__tuple_indices<_Indx...>, _Tp. { _VSTD::__swallow(__tuple_leaf<_Indx, _Tp>::swap(static_cast<__tuple_leaf<_Indx, _Tp>&>(__t))...); } + + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + void swap(const __tuple_impl& __t) const + _NOEXCEPT_(__all<__is_nothrow_swappable<const _Tp>::value...>::value) + { + _VSTD::__swallow(__tuple_leaf<_Indx, _Tp>::swap(static_cast<const __tuple_leaf<_Indx, _Tp>&>(__t))...); + } }; template<class _Dest, class _Source, size_t ..._Np> @@ -689,6 +751,7 @@ public: template <class _Alloc, template<class...> class _And = _And, __enable_if_t< _And<is_copy_constructible<_Tp>...>::value , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 tuple(allocator_arg_t, const _Alloc& __alloc, const tuple& __t) : __base_(allocator_arg_t(), __alloc, __t) { } @@ -696,30 +759,39 @@ public: template <class _Alloc, template<class...> class _And = _And, __enable_if_t< _And<is_move_constructible<_Tp>...>::value , int> = 0> + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 tuple(allocator_arg_t, const _Alloc& __alloc, tuple&& __t) : __base_(allocator_arg_t(), __alloc, _VSTD::move(__t)) { } // tuple(const tuple<U...>&) constructors (including allocator_arg_t variants) - template <class ..._Up> - struct _EnableCopyFromOtherTuple : _And< - _Not<is_same<tuple<_Tp...>, tuple<_Up...> > >, - _Lazy<_Or, - _BoolConstant<sizeof...(_Tp) != 1>, + + template <class _OtherTuple, class _DecayedOtherTuple = __uncvref_t<_OtherTuple>, class = void> + struct _EnableCtorFromUTypesTuple : false_type {}; + + template <class _OtherTuple, class... _Up> + struct _EnableCtorFromUTypesTuple<_OtherTuple, tuple<_Up...>, + // the length of the packs needs to checked first otherwise the 2 packs cannot be expanded simultaneously below + __enable_if_t<sizeof...(_Up) == sizeof...(_Tp)>> : _And< + // the two conditions below are not in spec. The purpose is to disable the UTypes Ctor when copy/move Ctor can work. + // Otherwise, is_constructible can trigger hard error in those cases https://godbolt.org/z/M94cGdKcE + _Not<is_same<_OtherTuple, const tuple&> >, + _Not<is_same<_OtherTuple, tuple&&> >, + is_constructible<_Tp, __copy_cvref_t<_OtherTuple, _Up> >..., + _Lazy<_Or, _BoolConstant<sizeof...(_Tp) != 1>, // _Tp and _Up are 1-element packs - the pack expansions look // weird to avoid tripping up the type traits in degenerate cases _Lazy<_And, - _Not<is_convertible<const tuple<_Up>&, _Tp> >..., - _Not<is_constructible<_Tp, const tuple<_Up>&> >... + _Not<is_same<_Tp, _Up> >..., + _Not<is_convertible<_OtherTuple, _Tp> >..., + _Not<is_constructible<_Tp, _OtherTuple> >... > - >, - is_constructible<_Tp, const _Up&>... - > { }; + > + > {}; template <class ..._Up, __enable_if_t< _And< - _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, - _EnableCopyFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple<const tuple<_Up...>&>, is_convertible<const _Up&, _Tp>... // explicit check >::value , int> = 0> @@ -731,8 +803,7 @@ public: template <class ..._Up, __enable_if_t< _And< - _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, - _EnableCopyFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple<const tuple<_Up...>&>, _Not<_Lazy<_And, is_convertible<const _Up&, _Tp>...> > // explicit check >::value , int> = 0> @@ -744,8 +815,7 @@ public: template <class ..._Up, class _Alloc, __enable_if_t< _And< - _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, - _EnableCopyFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple<const tuple<_Up...>&>, is_convertible<const _Up&, _Tp>... // explicit check >::value , int> = 0> @@ -756,8 +826,7 @@ public: template <class ..._Up, class _Alloc, __enable_if_t< _And< - _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, - _EnableCopyFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple<const tuple<_Up...>&>, _Not<_Lazy<_And, is_convertible<const _Up&, _Tp>...> > // explicit check >::value , int> = 0> @@ -766,26 +835,27 @@ public: : __base_(allocator_arg_t(), __a, __t) { } +#if _LIBCPP_STD_VER > 20 + // tuple(tuple<U...>&) constructors (including allocator_arg_t variants) + + template <class... _Up, enable_if_t< + _EnableCtorFromUTypesTuple<tuple<_Up...>&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!(is_convertible_v<_Up&, _Tp> && ...)) + tuple(tuple<_Up...>& __t) : __base_(__t) {} + + template <class _Alloc, class... _Up, enable_if_t< + _EnableCtorFromUTypesTuple<tuple<_Up...>&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!(is_convertible_v<_Up&, _Tp> && ...)) + tuple(allocator_arg_t, const _Alloc& __alloc, tuple<_Up...>& __t) : __base_(allocator_arg_t(), __alloc, __t) {} +#endif // _LIBCPP_STD_VER > 20 + // tuple(tuple<U...>&&) constructors (including allocator_arg_t variants) - template <class ..._Up> - struct _EnableMoveFromOtherTuple : _And< - _Not<is_same<tuple<_Tp...>, tuple<_Up...> > >, - _Lazy<_Or, - _BoolConstant<sizeof...(_Tp) != 1>, - // _Tp and _Up are 1-element packs - the pack expansions look - // weird to avoid tripping up the type traits in degenerate cases - _Lazy<_And, - _Not<is_convertible<tuple<_Up>, _Tp> >..., - _Not<is_constructible<_Tp, tuple<_Up> > >... - > - >, - is_constructible<_Tp, _Up>... - > { }; template <class ..._Up, __enable_if_t< _And< - _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, - _EnableMoveFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple<tuple<_Up...>&&>, is_convertible<_Up, _Tp>... // explicit check >::value , int> = 0> @@ -797,8 +867,7 @@ public: template <class ..._Up, __enable_if_t< _And< - _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, - _EnableMoveFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple<tuple<_Up...>&&>, _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check >::value , int> = 0> @@ -810,8 +879,7 @@ public: template <class _Alloc, class ..._Up, __enable_if_t< _And< - _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, - _EnableMoveFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple<tuple<_Up...>&&>, is_convertible<_Up, _Tp>... // explicit check >::value , int> = 0> @@ -822,8 +890,7 @@ public: template <class _Alloc, class ..._Up, __enable_if_t< _And< - _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, - _EnableMoveFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple<tuple<_Up...>&&>, _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check >::value , int> = 0> @@ -832,57 +899,77 @@ public: : __base_(allocator_arg_t(), __a, _VSTD::move(__t)) { } +#if _LIBCPP_STD_VER > 20 + // tuple(const tuple<U...>&&) constructors (including allocator_arg_t variants) + + template <class... _Up, enable_if_t< + _EnableCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!(is_convertible_v<const _Up&&, _Tp> && ...)) + tuple(const tuple<_Up...>&& __t) : __base_(std::move(__t)) {} + + template <class _Alloc, class... _Up, enable_if_t< + _EnableCtorFromUTypesTuple<const tuple<_Up...>&&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!(is_convertible_v<const _Up&&, _Tp> && ...)) + tuple(allocator_arg_t, const _Alloc& __alloc, const tuple<_Up...>&& __t) + : __base_(allocator_arg_t(), __alloc, std::move(__t)) {} +#endif // _LIBCPP_STD_VER > 20 + // tuple(const pair<U1, U2>&) constructors (including allocator_arg_t variants) - template <class _Up1, class _Up2, class ..._DependentTp> - struct _EnableImplicitCopyFromPair : _And< - is_constructible<_FirstType<_DependentTp...>, const _Up1&>, - is_constructible<_SecondType<_DependentTp...>, const _Up2&>, - is_convertible<const _Up1&, _FirstType<_DependentTp...> >, // explicit check - is_convertible<const _Up2&, _SecondType<_DependentTp...> > - > { }; - template <class _Up1, class _Up2, class ..._DependentTp> - struct _EnableExplicitCopyFromPair : _And< - is_constructible<_FirstType<_DependentTp...>, const _Up1&>, - is_constructible<_SecondType<_DependentTp...>, const _Up2&>, - _Not<is_convertible<const _Up1&, _FirstType<_DependentTp...> > >, // explicit check - _Not<is_convertible<const _Up2&, _SecondType<_DependentTp...> > > - > { }; + template <template <class...> class Pred, class _Pair, class _DecayedPair = __uncvref_t<_Pair>, class _Tuple = tuple> + struct _CtorPredicateFromPair : false_type{}; + + template <template <class...> class Pred, class _Pair, class _Up1, class _Up2, class _Tp1, class _Tp2> + struct _CtorPredicateFromPair<Pred, _Pair, pair<_Up1, _Up2>, tuple<_Tp1, _Tp2> > : _And< + Pred<_Tp1, __copy_cvref_t<_Pair, _Up1> >, + Pred<_Tp2, __copy_cvref_t<_Pair, _Up2> > + > {}; + + template <class _Pair> + struct _EnableCtorFromPair : _CtorPredicateFromPair<is_constructible, _Pair>{}; + + template <class _Pair> + struct _NothrowConstructibleFromPair : _CtorPredicateFromPair<is_nothrow_constructible, _Pair>{}; + + template <class _Pair, class _DecayedPair = __uncvref_t<_Pair>, class _Tuple = tuple> + struct _BothImplicitlyConvertible : false_type{}; + + template <class _Pair, class _Up1, class _Up2, class _Tp1, class _Tp2> + struct _BothImplicitlyConvertible<_Pair, pair<_Up1, _Up2>, tuple<_Tp1, _Tp2> > : _And< + is_convertible<__copy_cvref_t<_Pair, _Up1>, _Tp1>, + is_convertible<__copy_cvref_t<_Pair, _Up2>, _Tp2> + > {}; template <class _Up1, class _Up2, template<class...> class _And = _And, __enable_if_t< _And< - _BoolConstant<sizeof...(_Tp) == 2>, - _EnableImplicitCopyFromPair<_Up1, _Up2, _Tp...> + _EnableCtorFromPair<const pair<_Up1, _Up2>&>, + _BothImplicitlyConvertible<const pair<_Up1, _Up2>&> // explicit check >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 tuple(const pair<_Up1, _Up2>& __p) - _NOEXCEPT_((_And< - is_nothrow_constructible<_FirstType<_Tp...>, const _Up1&>, - is_nothrow_constructible<_SecondType<_Tp...>, const _Up2&> - >::value)) + _NOEXCEPT_((_NothrowConstructibleFromPair<const pair<_Up1, _Up2>&>::value)) : __base_(__p) { } template <class _Up1, class _Up2, template<class...> class _And = _And, __enable_if_t< _And< - _BoolConstant<sizeof...(_Tp) == 2>, - _EnableExplicitCopyFromPair<_Up1, _Up2, _Tp...> + _EnableCtorFromPair<const pair<_Up1, _Up2>&>, + _Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> > // explicit check >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 explicit tuple(const pair<_Up1, _Up2>& __p) - _NOEXCEPT_((_And< - is_nothrow_constructible<_FirstType<_Tp...>, const _Up1&>, - is_nothrow_constructible<_SecondType<_Tp...>, const _Up2&> - >::value)) + _NOEXCEPT_((_NothrowConstructibleFromPair<const pair<_Up1, _Up2>&>::value)) : __base_(__p) { } template <class _Alloc, class _Up1, class _Up2, template<class...> class _And = _And, __enable_if_t< _And< - _BoolConstant<sizeof...(_Tp) == 2>, - _EnableImplicitCopyFromPair<_Up1, _Up2, _Tp...> + _EnableCtorFromPair<const pair<_Up1, _Up2>&>, + _BothImplicitlyConvertible<const pair<_Up1, _Up2>&> // explicit check >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 @@ -892,8 +979,8 @@ public: template <class _Alloc, class _Up1, class _Up2, template<class...> class _And = _And, __enable_if_t< _And< - _BoolConstant<sizeof...(_Tp) == 2>, - _EnableExplicitCopyFromPair<_Up1, _Up2, _Tp...> + _EnableCtorFromPair<const pair<_Up1, _Up2>&>, + _Not<_BothImplicitlyConvertible<const pair<_Up1, _Up2>&> > // explicit check >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 @@ -901,57 +988,52 @@ public: : __base_(allocator_arg_t(), __a, __p) { } - // tuple(pair<U1, U2>&&) constructors (including allocator_arg_t variants) - template <class _Up1, class _Up2, class ..._DependentTp> - struct _EnableImplicitMoveFromPair : _And< - is_constructible<_FirstType<_DependentTp...>, _Up1>, - is_constructible<_SecondType<_DependentTp...>, _Up2>, - is_convertible<_Up1, _FirstType<_DependentTp...> >, // explicit check - is_convertible<_Up2, _SecondType<_DependentTp...> > - > { }; +#if _LIBCPP_STD_VER > 20 + // tuple(pair<U1, U2>&) constructors (including allocator_arg_t variants) + + template <class _U1, class _U2, enable_if_t< + _EnableCtorFromPair<pair<_U1, _U2>&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value) + tuple(pair<_U1, _U2>& __p) : __base_(__p) {} + + template <class _Alloc, class _U1, class _U2, enable_if_t< + _EnableCtorFromPair<std::pair<_U1, _U2>&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!_BothImplicitlyConvertible<pair<_U1, _U2>&>::value) + tuple(allocator_arg_t, const _Alloc& __alloc, pair<_U1, _U2>& __p) : __base_(allocator_arg_t(), __alloc, __p) {} +#endif - template <class _Up1, class _Up2, class ..._DependentTp> - struct _EnableExplicitMoveFromPair : _And< - is_constructible<_FirstType<_DependentTp...>, _Up1>, - is_constructible<_SecondType<_DependentTp...>, _Up2>, - _Not<is_convertible<_Up1, _FirstType<_DependentTp...> > >, // explicit check - _Not<is_convertible<_Up2, _SecondType<_DependentTp...> > > - > { }; + // tuple(pair<U1, U2>&&) constructors (including allocator_arg_t variants) template <class _Up1, class _Up2, template<class...> class _And = _And, __enable_if_t< _And< - _BoolConstant<sizeof...(_Tp) == 2>, - _EnableImplicitMoveFromPair<_Up1, _Up2, _Tp...> + _EnableCtorFromPair<pair<_Up1, _Up2>&&>, + _BothImplicitlyConvertible<pair<_Up1, _Up2>&&> // explicit check >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 tuple(pair<_Up1, _Up2>&& __p) - _NOEXCEPT_((_And< - is_nothrow_constructible<_FirstType<_Tp...>, _Up1>, - is_nothrow_constructible<_SecondType<_Tp...>, _Up2> - >::value)) + _NOEXCEPT_((_NothrowConstructibleFromPair<pair<_Up1, _Up2>&&>::value)) : __base_(_VSTD::move(__p)) { } template <class _Up1, class _Up2, template<class...> class _And = _And, __enable_if_t< _And< - _BoolConstant<sizeof...(_Tp) == 2>, - _EnableExplicitMoveFromPair<_Up1, _Up2, _Tp...> + _EnableCtorFromPair<pair<_Up1, _Up2>&&>, + _Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> > // explicit check >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 explicit tuple(pair<_Up1, _Up2>&& __p) - _NOEXCEPT_((_And< - is_nothrow_constructible<_FirstType<_Tp...>, _Up1>, - is_nothrow_constructible<_SecondType<_Tp...>, _Up2> - >::value)) + _NOEXCEPT_((_NothrowConstructibleFromPair<pair<_Up1, _Up2>&&>::value)) : __base_(_VSTD::move(__p)) { } template <class _Alloc, class _Up1, class _Up2, template<class...> class _And = _And, __enable_if_t< _And< - _BoolConstant<sizeof...(_Tp) == 2>, - _EnableImplicitMoveFromPair<_Up1, _Up2, _Tp...> + _EnableCtorFromPair<pair<_Up1, _Up2>&&>, + _BothImplicitlyConvertible<pair<_Up1, _Up2>&&> // explicit check >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 @@ -961,8 +1043,8 @@ public: template <class _Alloc, class _Up1, class _Up2, template<class...> class _And = _And, __enable_if_t< _And< - _BoolConstant<sizeof...(_Tp) == 2>, - _EnableExplicitMoveFromPair<_Up1, _Up2, _Tp...> + _EnableCtorFromPair<pair<_Up1, _Up2>&&>, + _Not<_BothImplicitlyConvertible<pair<_Up1, _Up2>&&> > // explicit check >::value , int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 @@ -970,6 +1052,23 @@ public: : __base_(allocator_arg_t(), __a, _VSTD::move(__p)) { } +#if _LIBCPP_STD_VER > 20 + // tuple(const pair<U1, U2>&&) constructors (including allocator_arg_t variants) + + template <class _U1, class _U2, enable_if_t< + _EnableCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value) + tuple(const pair<_U1, _U2>&& __p) : __base_(std::move(__p)) {} + + template <class _Alloc, class _U1, class _U2, enable_if_t< + _EnableCtorFromPair<const pair<_U1, _U2>&&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!_BothImplicitlyConvertible<const pair<_U1, _U2>&&>::value) + tuple(allocator_arg_t, const _Alloc& __alloc, const pair<_U1, _U2>&& __p) + : __base_(allocator_arg_t(), __alloc, std::move(__p)) {} +#endif // _LIBCPP_STD_VER > 20 + // [tuple.assign] _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 tuple& operator=(_If<_And<is_copy_assignable<_Tp>...>::value, tuple, __nat> const& __tuple) @@ -980,6 +1079,25 @@ public: return *this; } +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr + const tuple& operator=(tuple const& __tuple) const + requires (_And<is_copy_assignable<const _Tp>...>::value) { + std::__memberwise_copy_assign(*this, __tuple, typename __make_tuple_indices<sizeof...(_Tp)>::type()); + return *this; + } + + _LIBCPP_HIDE_FROM_ABI constexpr + const tuple& operator=(tuple&& __tuple) const + requires (_And<is_assignable<const _Tp&, _Tp>...>::value) { + std::__memberwise_forward_assign(*this, + std::move(__tuple), + __tuple_types<_Tp...>(), + typename __make_tuple_indices<sizeof...(_Tp)>::type()); + return *this; + } +#endif // _LIBCPP_STD_VER > 20 + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 tuple& operator=(_If<_And<is_move_assignable<_Tp>...>::value, tuple, __nat>&& __tuple) _NOEXCEPT_((_And<is_nothrow_move_assignable<_Tp>...>::value)) @@ -1021,38 +1139,89 @@ public: return *this; } - template<class _Up1, class _Up2, class _Dep = true_type, __enable_if_t< - _And<_Dep, - _BoolConstant<sizeof...(_Tp) == 2>, - is_assignable<_FirstType<_Tp..., _Dep>&, _Up1 const&>, - is_assignable<_SecondType<_Tp..., _Dep>&, _Up2 const&> - >::value + +#if _LIBCPP_STD_VER > 20 + template <class... _UTypes, enable_if_t< + _And<_BoolConstant<sizeof...(_Tp) == sizeof...(_UTypes)>, + is_assignable<const _Tp&, const _UTypes&>...>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + const tuple& operator=(const tuple<_UTypes...>& __u) const { + std::__memberwise_copy_assign(*this, + __u, + typename __make_tuple_indices<sizeof...(_Tp)>::type()); + return *this; + } + + template <class... _UTypes, enable_if_t< + _And<_BoolConstant<sizeof...(_Tp) == sizeof...(_UTypes)>, + is_assignable<const _Tp&, _UTypes>...>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + const tuple& operator=(tuple<_UTypes...>&& __u) const { + std::__memberwise_forward_assign(*this, + __u, + __tuple_types<_UTypes...>(), + typename __make_tuple_indices<sizeof...(_Tp)>::type()); + return *this; + } +#endif // _LIBCPP_STD_VER > 20 + + template <template<class...> class Pred, bool _Const, + class _Pair, class _DecayedPair = __uncvref_t<_Pair>, class _Tuple = tuple> + struct _AssignPredicateFromPair : false_type {}; + + template <template<class...> class Pred, bool _Const, + class _Pair, class _Up1, class _Up2, class _Tp1, class _Tp2> + struct _AssignPredicateFromPair<Pred, _Const, _Pair, pair<_Up1, _Up2>, tuple<_Tp1, _Tp2> > : + _And<Pred<__maybe_const<_Const, _Tp1>&, __copy_cvref_t<_Pair, _Up1> >, + Pred<__maybe_const<_Const, _Tp2>&, __copy_cvref_t<_Pair, _Up2> > + > {}; + + template <bool _Const, class _Pair> + struct _EnableAssignFromPair : _AssignPredicateFromPair<is_assignable, _Const, _Pair> {}; + + template <bool _Const, class _Pair> + struct _NothrowAssignFromPair : _AssignPredicateFromPair<is_nothrow_assignable, _Const, _Pair> {}; + +#if _LIBCPP_STD_VER > 20 + template <class _U1, class _U2, enable_if_t< + _EnableAssignFromPair<true, const pair<_U1, _U2>&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + const tuple& operator=(const pair<_U1, _U2>& __pair) const + noexcept(_NothrowAssignFromPair<true, const pair<_U1, _U2>&>::value) { + std::get<0>(*this) = __pair.first; + std::get<1>(*this) = __pair.second; + return *this; + } + + template <class _U1, class _U2, enable_if_t< + _EnableAssignFromPair<true, pair<_U1, _U2>&&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + const tuple& operator=(pair<_U1, _U2>&& __pair) const + noexcept(_NothrowAssignFromPair<true, pair<_U1, _U2>&&>::value) { + std::get<0>(*this) = std::move(__pair.first); + std::get<1>(*this) = std::move(__pair.second); + return *this; + } +#endif // _LIBCPP_STD_VER > 20 + + template<class _Up1, class _Up2, __enable_if_t< + _EnableAssignFromPair<false, pair<_Up1, _Up2> const&>::value ,int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 tuple& operator=(pair<_Up1, _Up2> const& __pair) - _NOEXCEPT_((_And< - is_nothrow_assignable<_FirstType<_Tp...>&, _Up1 const&>, - is_nothrow_assignable<_SecondType<_Tp...>&, _Up2 const&> - >::value)) + _NOEXCEPT_((_NothrowAssignFromPair<false, pair<_Up1, _Up2> const&>::value)) { _VSTD::get<0>(*this) = __pair.first; _VSTD::get<1>(*this) = __pair.second; return *this; } - template<class _Up1, class _Up2, class _Dep = true_type, __enable_if_t< - _And<_Dep, - _BoolConstant<sizeof...(_Tp) == 2>, - is_assignable<_FirstType<_Tp..., _Dep>&, _Up1>, - is_assignable<_SecondType<_Tp..., _Dep>&, _Up2> - >::value + template<class _Up1, class _Up2, __enable_if_t< + _EnableAssignFromPair<false, pair<_Up1, _Up2>&&>::value ,int> = 0> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 tuple& operator=(pair<_Up1, _Up2>&& __pair) - _NOEXCEPT_((_And< - is_nothrow_assignable<_FirstType<_Tp...>&, _Up1>, - is_nothrow_assignable<_SecondType<_Tp...>&, _Up2> - >::value)) + _NOEXCEPT_((_NothrowAssignFromPair<false, pair<_Up1, _Up2>&&>::value)) { _VSTD::get<0>(*this) = _VSTD::forward<_Up1>(__pair.first); _VSTD::get<1>(*this) = _VSTD::forward<_Up2>(__pair.second); @@ -1096,6 +1265,13 @@ public: _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void swap(tuple& __t) _NOEXCEPT_(__all<__is_nothrow_swappable<_Tp>::value...>::value) {__base_.swap(__t.__base_);} + +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr + void swap(const tuple& __t) const noexcept(__all<is_nothrow_swappable_v<const _Tp&>...>::value) { + __base_.swap(__t.__base_); + } +#endif // _LIBCPP_STD_VER > 20 }; template <> @@ -1118,6 +1294,9 @@ public: tuple(allocator_arg_t, const _Alloc&, array<_Up, 0>) _NOEXCEPT {} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 void swap(tuple&) _NOEXCEPT {} +#if _LIBCPP_STD_VER > 20 + _LIBCPP_HIDE_FROM_ABI constexpr void swap(const tuple&) const noexcept {} +#endif }; #if _LIBCPP_STD_VER > 20 @@ -1158,6 +1337,16 @@ swap(tuple<_Tp...>& __t, tuple<_Tp...>& __u) _NOEXCEPT_(__all<__is_nothrow_swappable<_Tp>::value...>::value) {__t.swap(__u);} +#if _LIBCPP_STD_VER > 20 +template <class... _Tp> +_LIBCPP_HIDE_FROM_ABI constexpr +enable_if_t<__all<is_swappable_v<const _Tp>...>::value, void> +swap(const tuple<_Tp...>& __lhs, const tuple<_Tp...>& __rhs) + noexcept(__all<is_nothrow_swappable_v<const _Tp>...>::value) { + __lhs.swap(__rhs); +} +#endif + // get template <size_t _Ip, class ..._Tp> |