From 15e946cd30589eb94de338c2b3f480b835517789 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 26 Sep 2024 15:05:44 +0800 Subject: [PATCH] Refactoring around `tuple-like`, `pair-like`, and `subrange` Effectively mirrors LLVM-85206. In the current standard wording, the "_`pair-like`_ but not `subrange`" pattern is used more often than plain _`pair-like`_. So it's probably worthwhile to carve out the `_Pair_like_non_subrange` concept. `_Tuple_like_non_subrange` seems less worthwhile, but it should be helpful in the constructors of `tuple`. Moreover, with `_Pair_like_non_subrange` carved out, we can put the definitions of `_Pair_like` in C++20 & 23 modes together in ``. `_Pair_like_non_subrange` should be also helpful for extracting the key object from pair-like construction argument via `_In_place_key_extract_map` (since C++23). I think this can be done in a future PR. Other changes: Renaming the template parameter of `subrange`'s conversion function to `_PairLike`, making the identifier `_Pair_like in MSVC STL always mean the concept. --- stl/inc/__msvc_iter_core.hpp | 5 ----- stl/inc/tuple | 25 ++++++++++--------------- stl/inc/utility | 35 ++++++++++++++++++----------------- stl/inc/xmemory | 2 +- stl/inc/xutility | 35 +++++++++++++++++++---------------- 5 files changed, 48 insertions(+), 54 deletions(-) diff --git a/stl/inc/__msvc_iter_core.hpp b/stl/inc/__msvc_iter_core.hpp index 619e97aa65..f62f6f0594 100644 --- a/stl/inc/__msvc_iter_core.hpp +++ b/stl/inc/__msvc_iter_core.hpp @@ -438,11 +438,6 @@ _EXPORT_STD using ranges::get; template constexpr bool _Is_subrange_v> = true; -#if _HAS_CXX23 -template -constexpr bool _Tuple_like_impl> = true; -#endif // _HAS_CXX23 - template struct tuple_size> : integral_constant {}; diff --git a/stl/inc/tuple b/stl/inc/tuple index 81e42e4f9c..5eb1453bd7 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -177,13 +177,12 @@ constexpr bool _Can_construct_values_from_tuple_like_v, _Other, #ifdef __EDG__ // TRANSITION, VSO-1900279 template -concept _Can_construct_from_tuple_like = - _Different_from<_TupleLike, _Tuple> && _Tuple_like<_TupleLike> && !_Is_subrange_v> - && (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>) ); +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 >> @@ -421,8 +420,7 @@ public: template , int> = 0> #else // ^^^ workaround / no workaround vvv template <_Different_from _Other> - requires _Tuple_like<_Other> && (!_Is_subrange_v>) - && (1 + sizeof...(_Rest) == tuple_size_v>) + 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 ^^^ @@ -527,8 +525,7 @@ public: template , int> = 0> #else // ^^^ workaround / no workaround vvv template _Other> - requires _Tuple_like<_Other> && (!_Is_subrange_v>) - && (1 + sizeof...(_Rest) == tuple_size_v>) + 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 ^^^ @@ -692,8 +689,7 @@ public: } template <_Different_from _Other> - requires _Tuple_like<_Other> && (!_Is_subrange_v>) - && (1 + sizeof...(_Rest) == tuple_size_v>) + 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)>{}); @@ -701,8 +697,7 @@ public: } template <_Different_from _Other> - requires _Tuple_like<_Other> && (!_Is_subrange_v>) - && (1 + sizeof...(_Rest) == tuple_size_v>) + 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)>{}); diff --git a/stl/inc/utility b/stl/inc/utility index c5f9265dcf..c994694268 100644 --- a/stl/inc/utility +++ b/stl/inc/utility @@ -205,28 +205,31 @@ constexpr bool _Is_subrange_v = false; #if _HAS_CXX23 template -constexpr bool _Tuple_like_impl = false; +constexpr bool _Tuple_like_non_subrange_impl = false; template -constexpr bool _Tuple_like_impl> = true; +constexpr bool _Tuple_like_non_subrange_impl> = true; template -constexpr bool _Tuple_like_impl> = true; +constexpr bool _Tuple_like_non_subrange_impl> = true; template -constexpr bool _Tuple_like_impl> = true; +constexpr bool _Tuple_like_non_subrange_impl> = true; template -concept _Tuple_like = _Tuple_like_impl>; +concept _Tuple_like_non_subrange = _Tuple_like_non_subrange_impl>; template -concept _Pair_like = _Tuple_like<_Ty> && tuple_size_v> == 2; +concept _Tuple_like = _Tuple_like_non_subrange<_Ty> || _Is_subrange_v>; + +template +concept _Pair_like_non_subrange = _Tuple_like_non_subrange<_Ty> && tuple_size_v> == 2; #ifdef __EDG__ // TRANSITION, VSO-1900279 template -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>()))>; +concept _Can_construct_from_pair_like = + _Pair_like_non_subrange<_PairLike> && is_constructible_v<_Ty1, decltype(_STD get<0>(_STD declval<_PairLike>()))> + && is_constructible_v<_Ty2, decltype(_STD get<1>(_STD declval<_PairLike>()))>; #endif // ^^^ workaround ^^^ #endif // _HAS_CXX23 #endif // _HAS_CXX20 @@ -302,9 +305,8 @@ struct pair { // store a pair of values #ifdef __EDG__ // TRANSITION, VSO-1900279 template , int> = 0> #else // ^^^ workaround / no workaround vvv - template <_Pair_like _Other> - requires conjunction_v>>, - is_constructible<_Ty1, decltype(_STD get<0>(_STD declval<_Other>()))>, + template <_Pair_like_non_subrange _Other> + requires conjunction_v(_STD declval<_Other>()))>, is_constructible<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>> #endif // ^^^ no workaround ^^^ constexpr explicit(!conjunction_v(_STD declval<_Other>())), _Ty1>, @@ -422,9 +424,8 @@ struct pair { // store a pair of values return *this; } - template <_Pair_like _Other> - requires _Different_from<_Other, pair> && (!_Is_subrange_v>) - && is_assignable_v<_Ty1&, decltype(_STD get<0>(_STD declval<_Other>()))> + template <_Pair_like_non_subrange _Other> + requires _Different_from<_Other, pair> && is_assignable_v<_Ty1&, decltype(_STD get<0>(_STD declval<_Other>()))> && is_assignable_v<_Ty2&, decltype(_STD get<1>(_STD declval<_Other>()))> constexpr pair& operator=(_Other&& _Right) noexcept(is_nothrow_assignable_v<_Ty1&, decltype(_STD get<0>(_STD declval<_Other>()))> @@ -434,8 +435,8 @@ struct pair { // store a pair of values return *this; } - template <_Pair_like _Other> - requires _Different_from<_Other, pair> && (!_Is_subrange_v>) + template <_Pair_like_non_subrange _Other> + requires _Different_from<_Other, pair> && is_assignable_v(_STD declval<_Other>()))> && is_assignable_v(_STD declval<_Other>()))> constexpr const pair& operator=(_Other&& _Right) const noexcept( diff --git a/stl/inc/xmemory b/stl/inc/xmemory index 3aa11f488c..48b669864d 100644 --- a/stl/inc/xmemory +++ b/stl/inc/xmemory @@ -2435,7 +2435,7 @@ _NODISCARD constexpr auto uses_allocator_construction_args( _EXPORT_STD template <_Cv_std_pair _Ty, class _Alloc, _Usable_for_pair_like_overload _Uty> _NODISCARD constexpr auto uses_allocator_construction_args(const _Alloc& _Al, _Uty&& _Ux) noexcept { #if _HAS_CXX23 - if constexpr (_Pair_like<_Uty> && !_Is_subrange_v>) { + if constexpr (_Pair_like_non_subrange<_Uty>) { // equivalent to // return _STD uses_allocator_construction_args<_Ty>(_Al, piecewise_construct, // _STD forward_as_tuple(_STD get<0>(_STD forward<_Uty>(_Ux)), diff --git a/stl/inc/xutility b/stl/inc/xutility index 6e791d549a..feee3de613 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -3874,6 +3874,21 @@ namespace ranges { }; } // namespace ranges +#if _HAS_CXX23 +template +concept _Pair_like = _Tuple_like<_Ty> && tuple_size_v> == 2; +#else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv +template +concept _Pair_like = !is_reference_v<_Ty> && requires(_Ty __t) { + typename tuple_size<_Ty>::type; + requires derived_from, integral_constant>; + typename tuple_element_t<0, remove_const_t<_Ty>>; + typename tuple_element_t<1, remove_const_t<_Ty>>; + { _STD get<0>(__t) } -> convertible_to&>; + { _STD get<1>(__t) } -> convertible_to&>; +}; +#endif // ^^^ !_HAS_CXX23 ^^^ + namespace ranges { template concept _Uses_nonqualification_pointer_conversion = @@ -3884,18 +3899,6 @@ namespace ranges { concept _Convertible_to_non_slicing = convertible_to<_From, _To> && !_Uses_nonqualification_pointer_conversion, decay_t<_To>>; -#if !_HAS_CXX23 - template - concept _Pair_like = !is_reference_v<_Ty> && requires(_Ty __t) { - typename tuple_size<_Ty>::type; - requires derived_from, integral_constant>; - typename tuple_element_t<0, remove_const_t<_Ty>>; - typename tuple_element_t<1, remove_const_t<_Ty>>; - { _STD get<0>(__t) } -> convertible_to&>; - { _STD get<1>(__t) } -> convertible_to&>; - }; -#endif // !_HAS_CXX23 - template concept _Pair_like_convertible_from = !range<_Ty> #if _HAS_CXX23 @@ -3989,10 +3992,10 @@ namespace ranges { requires (_Ki == subrange_kind::sized) : subrange{_RANGES begin(_Val), _RANGES end(_Val), _Count} {} - template <_Different_from _Pair_like> - requires _Pair_like_convertible_from<_Pair_like, const _It&, const _Se&> - constexpr operator _Pair_like() const { - return _Pair_like(_First, _Last); + template <_Different_from _PairLike> + requires _Pair_like_convertible_from<_PairLike, const _It&, const _Se&> + constexpr operator _PairLike() const { + return _PairLike(_First, _Last); } _NODISCARD constexpr _It begin() const