diff --git a/libcxx/include/tuple b/libcxx/include/tuple --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -25,14 +25,24 @@ explicit(see-below) tuple(U&&...); // constexpr in C++14 tuple(const tuple&) = default; tuple(tuple&&) = default; + + template + constexpr explicit(see-below) tuple(tuple&); // C++23 template explicit(see-below) tuple(const tuple&); // constexpr in C++14 template explicit(see-below) tuple(tuple&&); // constexpr in C++14 + template + constexpr explicit(see-below) tuple(const tuple&&); // C++23 + + template + constexpr explicit(see-below) tuple(pair&); // iff sizeof...(Types) == 2 // C++23 template explicit(see-below) tuple(const pair&); // iff sizeof...(T) == 2 // constexpr in C++14 template explicit(see-below) tuple(pair&&); // iff sizeof...(T) == 2 // constexpr in C++14 + template + constexpr explicit(see-below) tuple(const pair&&); // iff sizeof...(Types) == 2 // C++23 // allocator-extended constructors template @@ -45,25 +55,47 @@ tuple(allocator_arg_t, const Alloc& a, const tuple&); // constexpr in C++20 template tuple(allocator_arg_t, const Alloc& a, tuple&&); // constexpr in C++20 + template + constexpr explicit(see-below) + tuple(allocator_arg_t, const Alloc& a, tuple&); // C++23 template explicit(see-below) tuple(allocator_arg_t, const Alloc& a, const tuple&); // constexpr in C++20 template explicit(see-below) tuple(allocator_arg_t, const Alloc& a, tuple&&); // constexpr in C++20 + template + constexpr explicit(see-below) + tuple(allocator_arg_t, const Alloc& a, const tuple&&); // C++23 + template + constexpr explicit(see-below) + tuple(allocator_arg_t, const Alloc& a, pair&); // C++23 template explicit(see-below) tuple(allocator_arg_t, const Alloc& a, const pair&); // constexpr in C++20 template explicit(see-below) tuple(allocator_arg_t, const Alloc& a, pair&&); // constexpr in C++20 + template + constexpr explicit(see-below) + tuple(allocator_arg_t, const Alloc& a, const pair&&); // 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 && ...); // constexpr in C++20 + constexpr const tuple& operator=(tuple&&) const; // C++23 template tuple& operator=(const tuple&); // constexpr in C++20 + template + constexpr const tuple& operator=(const tuple&) const; // C++23 template tuple& operator=(tuple&&); // constexpr in C++20 + template + constexpr const tuple& operator=(tuple&&) const; // C++23 template tuple& operator=(const pair&); // iff sizeof...(T) == 2 // constexpr in C++20 + template + constexpr const tuple& operator=(const pair&) const; // iff sizeof...(Types) == 2 // C++23 template tuple& operator=(pair&&); // iff sizeof...(T) == 2 // constexpr in C++20 + template + constexpr const tuple& operator=(pair&&) const; // iff sizeof...(Types) == 2 // C++23 template tuple& operator=(array const&) // iff sizeof...(T) == N, EXTENSION @@ -71,6 +103,7 @@ tuple& operator=(array&&) // iff sizeof...(T) == N, EXTENSION void swap(tuple&) noexcept(AND(swap(declval(), declval())...)); // constexpr in C++20 + constexpr void swap(const tuple&) const noexcept(see-below); // C++23 }; @@ -161,6 +194,9 @@ void swap(tuple& x, tuple& y) noexcept(noexcept(x.swap(y))); +template + constexpr void swap(const tuple& x, const tuple& y) noexcept(see-below); // C++23 + } // std */ @@ -219,6 +255,13 @@ swap(__x.get(), __y.get()); } +template +_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::value) { + swap(__x.get(), __y.get()); +} + template class __tuple_leaf { @@ -307,6 +350,12 @@ return 0; } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + int swap(const __tuple_leaf& __t) const _NOEXCEPT_(__is_nothrow_swappable::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_;} }; @@ -373,6 +422,12 @@ return 0; } + _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 + int swap(const __tuple_leaf& __rhs) const _NOEXCEPT_(__is_nothrow_swappable::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(*this);} }; @@ -463,6 +518,13 @@ { _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::value...>::value) + { + _VSTD::__swallow(__tuple_leaf<_Indx, _Tp>::swap(static_cast&>(__t))...); + } }; template @@ -698,6 +760,7 @@ template class _And = _And, __enable_if_t< _And...>::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) { } @@ -705,30 +768,39 @@ template class _And = _And, __enable_if_t< _And...>::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&) constructors (including allocator_arg_t variants) - template - struct _EnableCopyFromOtherTuple : _And< - _Not, tuple<_Up...> > >, - _Lazy<_Or, - _BoolConstant, + + template , class = void> + struct _EnableCtorFromUTypesTuple : false_type {}; + + template + 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> : _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 >, + _Not >, + is_constructible<_Tp, __copy_cvref_t<_OtherTuple, _Up> >..., + _Lazy<_Or, _BoolConstant, // _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&, _Tp> >..., - _Not&> >... + _Not >..., + _Not >..., + _Not >... > - >, - is_constructible<_Tp, const _Up&>... - > { }; + > + > {}; template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple&>, is_convertible... // explicit check >::value , int> = 0> @@ -740,8 +812,7 @@ template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple&>, _Not<_Lazy<_And, is_convertible...> > // explicit check >::value , int> = 0> @@ -753,8 +824,7 @@ template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple&>, is_convertible... // explicit check >::value , int> = 0> @@ -765,8 +835,7 @@ template , - _EnableCopyFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple&>, _Not<_Lazy<_And, is_convertible...> > // explicit check >::value , int> = 0> @@ -775,26 +844,27 @@ : __base_(allocator_arg_t(), __a, __t) { } +#if _LIBCPP_STD_VER > 20 + // tuple(tuple&) constructors (including allocator_arg_t variants) + + template &>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!(is_convertible_v<_Up&, _Tp> && ...)) + tuple(tuple<_Up...>& __t) : __base_(__t) {} + + template &>::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&&) constructors (including allocator_arg_t variants) - template - struct _EnableMoveFromOtherTuple : _And< - _Not, tuple<_Up...> > >, - _Lazy<_Or, - _BoolConstant, - // _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, _Tp> >..., - _Not > >... - > - >, - is_constructible<_Tp, _Up>... - > { }; template , - _EnableMoveFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple&&>, is_convertible<_Up, _Tp>... // explicit check >::value , int> = 0> @@ -806,8 +876,7 @@ template , - _EnableMoveFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple&&>, _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check >::value , int> = 0> @@ -819,8 +888,7 @@ template , - _EnableMoveFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple&&>, is_convertible<_Up, _Tp>... // explicit check >::value , int> = 0> @@ -831,8 +899,7 @@ template , - _EnableMoveFromOtherTuple<_Up...>, + _EnableCtorFromUTypesTuple&&>, _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check >::value , int> = 0> @@ -841,57 +908,77 @@ : __base_(allocator_arg_t(), __a, _VSTD::move(__t)) { } +#if _LIBCPP_STD_VER > 20 + // tuple(const tuple&&) constructors (including allocator_arg_t variants) + + template &&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!(is_convertible_v && ...)) + tuple(const tuple<_Up...>&& __t) : __base_(std::move(__t)) {} + + template &&>::value>* = nullptr> + _LIBCPP_HIDE_FROM_ABI constexpr + explicit(!(is_convertible_v && ...)) + 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&) constructors (including allocator_arg_t variants) - template - struct _EnableImplicitCopyFromPair : _And< - is_constructible<_FirstType<_DependentTp...>, const _Up1&>, - is_constructible<_SecondType<_DependentTp...>, const _Up2&>, - is_convertible >, // explicit check - is_convertible > - > { }; - template - struct _EnableExplicitCopyFromPair : _And< - is_constructible<_FirstType<_DependentTp...>, const _Up1&>, - is_constructible<_SecondType<_DependentTp...>, const _Up2&>, - _Not > >, // explicit check - _Not > > - > { }; + template