diff --git a/stl/inc/utility b/stl/inc/utility index 1ad3d703bcf..f3bfe433fee 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -208,9 +208,9 @@ concept _Pair_like = _Tuple_like<_Ty> && tuple_size_v> == 2; #ifdef __clang__ // TRANSITION, LLVM-59827 template -concept _Can_construct_from_pair_like = - _Pair_like<_PairLike> && is_constructible_v<_Ty1, decltype(_STD get<0>(_STD declval<_PairLike>()))> - && is_constructible_v<_Ty2, decltype(_STD get<1>(_STD declval<_PairLike>()))>; +concept _Can_construct_from_pair_like = _Pair_like<_PairLike> && (!_Is_subrange_v>) + && is_constructible_v<_Ty1, decltype(_STD get<0>(_STD declval<_PairLike>()))> + && is_constructible_v<_Ty2, decltype(_STD get<1>(_STD declval<_PairLike>()))>; #endif // __clang__ #endif // _HAS_CXX23 #endif // __cpp_lib_concepts @@ -288,7 +288,8 @@ struct pair { // store a pair of values template , int> = 0> #else // ^^^ workaround / no workaround vvv template <_Pair_like _Other> - requires conjunction_v(_STD declval<_Other>()))>, + requires conjunction_v>>, + is_constructible<_Ty1, decltype(_STD get<0>(_STD declval<_Other>()))>, is_constructible<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>> #endif // __clang__ constexpr explicit(!conjunction_v(_STD declval<_Other>())), _Ty1>, diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 4ab17c0a8e2..c809f772e96 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -2304,8 +2304,13 @@ _NODISCARD constexpr auto uses_allocator_construction_args( const _Alloc& _Al, const pair<_Uty1, _Uty2>&& _Pair) noexcept; #endif // _HAS_CXX23 +#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 +_EXPORT_STD template + requires _Is_cv_pair<_Ty> && (_Pair_like<_Uty> || !_Is_deducible_as_pair<_Uty&>) +#else // ^^^ C++23 with concepts / C++20 or no concepts vvv _EXPORT_STD template && !_Is_deducible_as_pair<_Uty&>, int> = 0> +#endif // ^^^ C++20 or no concepts ^^^ _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Uty&& _Ux) noexcept; _EXPORT_STD template , int> = 0> @@ -2390,41 +2395,60 @@ _NODISCARD constexpr auto uses_allocator_construction_args( } #endif // _HAS_CXX23 +#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 +_EXPORT_STD template + requires _Is_cv_pair<_Ty> && (_Pair_like<_Uty> || !_Is_deducible_as_pair<_Uty&>) +#else // ^^^ C++23 with concepts / C++20 or no concepts vvv _EXPORT_STD template && !_Is_deducible_as_pair<_Uty&>, int>> +#endif // ^^^ C++20 or no concepts ^^^ _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Uty&& _Ux) noexcept { - struct _Pair_remaker { - const _Alloc& _Al; - _Uty& _Ux; - - constexpr operator remove_cv_t<_Ty>() const { - using _Pair_t = remove_cv_t<_Ty>; - static_assert(_Is_normally_bindable<_Pair_t, _Uty>, - "The argument must be bindable to a reference to the std::pair type."); - - using _Pair_first_t = typename _Pair_t::first_type; - using _Pair_second_t = typename _Pair_t::second_type; - using _Pair_ref_t = _Normally_bound_ref<_Pair_t, _Uty>; - _Pair_ref_t _Pair_ref = _STD forward<_Uty>(_Ux); - if constexpr (is_same_v<_Pair_ref_t, const _Pair_t&>) { - // equivalent to - // return _STD make_obj_using_allocator<_Pair_t>(_Al, _Pair_ref); - return _Pair_t{piecewise_construct, - _STD uses_allocator_construction_args<_Pair_first_t>(_Al, _Pair_ref.first), - _STD uses_allocator_construction_args<_Pair_second_t>(_Al, _Pair_ref.second)}; - } else { - // equivalent to - // return _STD make_obj_using_allocator<_Pair_t>(_Al, _STD move(_Pair_ref)); - return _Pair_t{piecewise_construct, - _STD uses_allocator_construction_args<_Pair_first_t>(_Al, _STD get<0>(_STD move(_Pair_ref))), - _STD uses_allocator_construction_args<_Pair_second_t>(_Al, _STD get<1>(_STD move(_Pair_ref)))}; +#if _HAS_CXX23 && defined(__cpp_lib_concepts) + if constexpr (_Pair_like<_Uty> && !_Is_subrange_v>) { + // equivalent to + // return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, + // _STD forward_as_tuple(_STD get<0>(_STD forward<_Uty>(_Ux)), + // _STD forward_as_tuple(_STD get<1>(_STD forward<_Uty>(_Ux))); + return _STD make_tuple(piecewise_construct, + _STD uses_allocator_construction_args(_Al, _STD get<0>(_STD forward<_Uty>(_Ux))), + _STD uses_allocator_construction_args( + _Al, _STD get<1>(_STD forward<_Uty>(_Ux)))); + } else +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) + { + struct _Pair_remaker { + const _Alloc& _Al; + _Uty& _Ux; + + constexpr operator remove_cv_t<_Ty>() const { + using _Pair_t = remove_cv_t<_Ty>; + static_assert(_Is_normally_bindable<_Pair_t, _Uty>, + "The argument must be bindable to a reference to the std::pair type."); + + using _Pair_first_t = typename _Pair_t::first_type; + using _Pair_second_t = typename _Pair_t::second_type; + using _Pair_ref_t = _Normally_bound_ref<_Pair_t, _Uty>; + _Pair_ref_t _Pair_ref = _STD forward<_Uty>(_Ux); + if constexpr (is_same_v<_Pair_ref_t, const _Pair_t&>) { + // equivalent to + // return _STD make_obj_using_allocator<_Pair_t>(_Al, _Pair_ref); + return _Pair_t{piecewise_construct, + _STD uses_allocator_construction_args<_Pair_first_t>(_Al, _Pair_ref.first), + _STD uses_allocator_construction_args<_Pair_second_t>(_Al, _Pair_ref.second)}; + } else { + // equivalent to + // return _STD make_obj_using_allocator<_Pair_t>(_Al, _STD move(_Pair_ref)); + return _Pair_t{piecewise_construct, + _STD uses_allocator_construction_args<_Pair_first_t>(_Al, _STD get<0>(_STD move(_Pair_ref))), + _STD uses_allocator_construction_args<_Pair_second_t>(_Al, _STD get<1>(_STD move(_Pair_ref)))}; + } } - } - }; + }; - // equivalent to - // return _STD make_tuple(_Pair_remaker{_Al, _Ux}); - return tuple<_Pair_remaker>({_Al, _Ux}); + // equivalent to + // return _STD make_tuple(_Pair_remaker{_Al, _Ux}); + return tuple<_Pair_remaker>({_Al, _Ux}); + } } _EXPORT_STD template diff --git a/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp b/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp index 351fa0edbb5..352327d2a47 100644 --- a/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp +++ b/tests/std/tests/P0475R1_P0591R4_uses_allocator_construction/test.cpp @@ -177,6 +177,43 @@ constexpr bool test_P0591R4() { } #endif // _HAS_CXX23 +#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 + { // pair(PairLike&&) overload + tuple tpl(i, i); + auto tuple14 = uses_allocator_construction_args>(alloc, tpl); + static_assert( + is_same_v, AllocatorArgConstructArgs>>); + + auto tuple15 = uses_allocator_construction_args>(alloc, tpl); + static_assert(is_same_v>>); + + auto tuple16 = uses_allocator_construction_args>(alloc, move(tpl)); + static_assert( + is_same_v, MovedAllocatorArgConstructArgs>>); + + auto tuple17 = uses_allocator_construction_args>(alloc, move(tpl)); + static_assert( + is_same_v>>); + + auto tuple18 = uses_allocator_construction_args>(alloc, as_const(tpl)); + static_assert(is_same_v, ConstAllocatorArgConstructArgs>>); + + auto tuple19 = uses_allocator_construction_args>(alloc, as_const(tpl)); + static_assert( + is_same_v>>); + + auto tuple20 = + uses_allocator_construction_args>(alloc, move(as_const(tpl))); + static_assert(is_same_v, MovedConstAllocatorArgConstructArgs>>); + + auto tuple21 = uses_allocator_construction_args>(alloc, move(as_const(tpl))); + static_assert(is_same_v>>); + } +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) + { auto obj1 = make_obj_using_allocator(alloc, i); static_assert(is_same_v);