Skip to content

Commit 1072296

Browse files
P2165R4: Compatibility Between tuple, pair, And tuple-like Objects (changes to pair only) (#3323)
Co-authored-by: Stephan T. Lavavej <[email protected]>
1 parent 31defd3 commit 1072296

File tree

10 files changed

+318
-54
lines changed

10 files changed

+318
-54
lines changed

stl/inc/__msvc_iter_core.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,9 @@ namespace ranges {
429429

430430
_EXPORT_STD using ranges::get;
431431

432+
template <class _It, class _Se, ranges::subrange_kind _Ki>
433+
inline constexpr bool _Is_subrange_v<ranges::subrange<_It, _Se, _Ki>> = true;
434+
432435
template <class _It, class _Se, ranges::subrange_kind _Ki>
433436
struct tuple_size<ranges::subrange<_It, _Se, _Ki>> : integral_constant<size_t, 2> {};
434437

stl/inc/ranges

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2713,11 +2713,6 @@ namespace ranges {
27132713
inline constexpr bool enable_borrowed_range<take_view<_Rng>> = enable_borrowed_range<_Rng>;
27142714

27152715
namespace views {
2716-
template <class>
2717-
inline constexpr bool _Is_subrange = false;
2718-
template <class _It, class _Se, subrange_kind _Ki>
2719-
inline constexpr bool _Is_subrange<subrange<_It, _Se, _Ki>> = true;
2720-
27212716
template <class _Rng>
27222717
concept _Random_sized_range = random_access_range<_Rng> && sized_range<_Rng>;
27232718

@@ -2745,7 +2740,7 @@ namespace ranges {
27452740
} else if constexpr (_Random_sized_range<_Ty> && _Is_specialization_v<_Ty, iota_view>) {
27462741
return {_St::_Reconstruct_iota_view,
27472742
noexcept(_RANGES begin(_STD declval<_Rng&>()) + _RANGES distance(_STD declval<_Rng&>()))};
2748-
} else if constexpr (_Random_sized_range<_Ty> && _Is_subrange<_Ty>) {
2743+
} else if constexpr (_Random_sized_range<_Ty> && _Is_subrange_v<_Ty>) {
27492744
return {_St::_Reconstruct_subrange,
27502745
noexcept(subrange(_RANGES begin(_STD declval<_Rng&>()),
27512746
_RANGES begin(_STD declval<_Rng&>()) + _RANGES distance(_STD declval<_Rng&>())))};
@@ -3121,7 +3116,7 @@ namespace ranges {
31213116
return {_St::_Reconstruct_span, true};
31223117
} else if constexpr (_Is_specialization_v<_Ty, basic_string_view>) {
31233118
return {_St::_Reconstruct_other, true};
3124-
} else if constexpr (_Random_sized_range<_Ty> && _Is_subrange<_Ty>) {
3119+
} else if constexpr (_Random_sized_range<_Ty> && _Is_subrange_v<_Ty>) {
31253120
if constexpr (sized_sentinel_for<sentinel_t<_Ty>, iterator_t<_Ty>>) {
31263121
return {_St::_Reconstruct_subrange,
31273122
noexcept(_Ty(_RANGES begin(_STD declval<_Rng&>()) + _RANGES distance(_STD declval<_Rng&>()),

stl/inc/span

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,6 @@ struct _Span_extent_type<_Ty, dynamic_extent> {
222222
size_t _Mysize{0};
223223
};
224224

225-
_EXPORT_STD template <class _Ty, size_t _Size>
226-
class array;
227-
228225
_EXPORT_STD template <class _Ty, size_t _Extent>
229226
class span;
230227

@@ -242,12 +239,6 @@ inline constexpr bool _Is_span_v = false;
242239
template <class _Ty, size_t _Extent>
243240
inline constexpr bool _Is_span_v<span<_Ty, _Extent>> = true;
244241

245-
template <class>
246-
inline constexpr bool _Is_std_array_v = false;
247-
248-
template <class _Ty, size_t _Size>
249-
inline constexpr bool _Is_std_array_v<array<_Ty, _Size>> = true;
250-
251242
// clang-format off
252243
template <class _It, class _Ty>
253244
concept _Span_compatible_iterator = contiguous_iterator<_It>

stl/inc/tuple

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -179,9 +179,6 @@ struct _Alloc_unpack_tuple_t {
179179
explicit _Alloc_unpack_tuple_t() = default;
180180
}; // tag type to disambiguate construction (from an allocator and unpacking a tuple/pair)
181181

182-
_EXPORT_STD template <class... _Types>
183-
class tuple;
184-
185182
template <>
186183
class tuple<> { // empty tuple
187184
public:
@@ -824,21 +821,6 @@ _NODISCARD constexpr tuple<_Types&&...> forward_as_tuple(_Types&&... _Args) noex
824821
return tuple<_Types&&...>(_STD forward<_Types>(_Args)...);
825822
}
826823

827-
_EXPORT_STD template <class _Ty, size_t _Size>
828-
class array;
829-
830-
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
831-
_NODISCARD constexpr _Ty& get(array<_Ty, _Size>& _Arr) noexcept;
832-
833-
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
834-
_NODISCARD constexpr const _Ty& get(const array<_Ty, _Size>& _Arr) noexcept;
835-
836-
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
837-
_NODISCARD constexpr _Ty&& get(array<_Ty, _Size>&& _Arr) noexcept;
838-
839-
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
840-
_NODISCARD constexpr const _Ty&& get(const array<_Ty, _Size>&& _Arr) noexcept;
841-
842824
template <class _Ty, class _Kx_arg, class _Ix_arg, size_t _Ix_next, class... _Sequences>
843825
struct _Tuple_cat2;
844826

stl/inc/utility

Lines changed: 118 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,87 @@ struct uses_allocator : _Has_allocator_type<_Ty, _Alloc>::type {
134134
_EXPORT_STD template <class _Ty, class _Alloc>
135135
_INLINE_VAR constexpr bool uses_allocator_v = uses_allocator<_Ty, _Alloc>::value;
136136

137-
_EXPORT_STD template <class...>
137+
_EXPORT_STD template <class... _Types>
138138
class tuple;
139139

140+
_EXPORT_STD template <class _Ty1, class _Ty2>
141+
struct pair;
142+
143+
_EXPORT_STD template <class _Ty, size_t _Size>
144+
class array;
145+
146+
_EXPORT_STD template <class _Tuple>
147+
struct tuple_size;
148+
149+
_EXPORT_STD template <class _Ty>
150+
_INLINE_VAR constexpr size_t tuple_size_v = tuple_size<_Ty>::value;
151+
152+
_EXPORT_STD template <size_t _Index, class _Tuple>
153+
struct tuple_element;
154+
155+
_EXPORT_STD template <size_t _Index, class _Tuple>
156+
using tuple_element_t = typename tuple_element<_Index, _Tuple>::type;
157+
140158
_EXPORT_STD /* TRANSITION, VSO-1538698 */ template <size_t _Index, class... _Types>
141159
_NODISCARD constexpr auto&& _Tuple_get(tuple<_Types...>&& _Tuple) noexcept;
142160

161+
_EXPORT_STD template <size_t _Index, class... _Types>
162+
_NODISCARD constexpr tuple_element_t<_Index, tuple<_Types...>>& get(tuple<_Types...>& _Tuple) noexcept;
163+
164+
_EXPORT_STD template <size_t _Index, class... _Types>
165+
_NODISCARD constexpr const tuple_element_t<_Index, tuple<_Types...>>& get(const tuple<_Types...>& _Tuple) noexcept;
166+
167+
_EXPORT_STD template <size_t _Index, class... _Types>
168+
_NODISCARD constexpr tuple_element_t<_Index, tuple<_Types...>>&& get(tuple<_Types...>&& _Tuple) noexcept;
169+
170+
_EXPORT_STD template <size_t _Index, class... _Types>
171+
_NODISCARD constexpr const tuple_element_t<_Index, tuple<_Types...>>&& get(const tuple<_Types...>&& _Tuple) noexcept;
172+
173+
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
174+
_NODISCARD constexpr _Ty& get(array<_Ty, _Size>& _Arr) noexcept;
175+
176+
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
177+
_NODISCARD constexpr const _Ty& get(const array<_Ty, _Size>& _Arr) noexcept;
178+
179+
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
180+
_NODISCARD constexpr _Ty&& get(array<_Ty, _Size>&& _Arr) noexcept;
181+
182+
_EXPORT_STD template <size_t _Idx, class _Ty, size_t _Size>
183+
_NODISCARD constexpr const _Ty&& get(const array<_Ty, _Size>&& _Arr) noexcept;
184+
185+
#ifdef __cpp_lib_concepts
186+
template <class _Ty1, class _Ty2>
187+
concept _Different_from = (!same_as<remove_cvref_t<_Ty1>, remove_cvref_t<_Ty2>>);
188+
189+
template <class>
190+
inline constexpr bool _Is_std_array_v = false;
191+
192+
template <class _Ty, size_t _Size>
193+
inline constexpr bool _Is_std_array_v<array<_Ty, _Size>> = true;
194+
195+
template <class>
196+
inline constexpr bool _Is_subrange_v = false;
197+
198+
#if _HAS_CXX23
199+
template <class _Ty>
200+
inline constexpr bool _Tuple_like_impl =
201+
_Is_specialization_v<_Ty, tuple> || _Is_specialization_v<_Ty, pair> || _Is_std_array_v<_Ty> || _Is_subrange_v<_Ty>;
202+
203+
template <class _Ty>
204+
concept _Tuple_like = _Tuple_like_impl<remove_cvref_t<_Ty>>;
205+
206+
template <class _Ty>
207+
concept _Pair_like = _Tuple_like<_Ty> && tuple_size_v<remove_cvref_t<_Ty>> == 2;
208+
209+
#ifdef __clang__ // TRANSITION, LLVM-59827
210+
template <class _PairLike, class _Ty1, class _Ty2>
211+
concept _Can_construct_from_pair_like =
212+
_Pair_like<_PairLike> && is_constructible_v<_Ty1, decltype(_STD get<0>(_STD declval<_PairLike>()))>
213+
&& is_constructible_v<_Ty2, decltype(_STD get<1>(_STD declval<_PairLike>()))>;
214+
#endif // __clang__
215+
#endif // _HAS_CXX23
216+
#endif // __cpp_lib_concepts
217+
143218
_EXPORT_STD template <class _Ty1, class _Ty2>
144219
struct pair { // store a pair of values
145220
using first_type = _Ty1;
@@ -207,6 +282,22 @@ struct pair { // store a pair of values
207282
pair(const pair<_Other1, _Other2>&& _Right) noexcept(is_nothrow_constructible_v<_Ty1, const _Other1>&&
208283
is_nothrow_constructible_v<_Ty2, const _Other2>) // strengthened
209284
: first(_STD forward<const _Other1>(_Right.first)), second(_STD forward<const _Other2>(_Right.second)) {}
285+
286+
#ifdef __cpp_lib_concepts
287+
#ifdef __clang__ // TRANSITION, LLVM-59827
288+
template <class _Other, enable_if_t<_Can_construct_from_pair_like<_Other, _Ty1, _Ty2>, int> = 0>
289+
#else // ^^^ workaround / no workaround vvv
290+
template <_Pair_like _Other>
291+
requires conjunction_v<is_constructible<_Ty1, decltype(_STD get<0>(_STD declval<_Other>()))>,
292+
is_constructible<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>>
293+
#endif // __clang__
294+
constexpr explicit(!conjunction_v<is_convertible<decltype(_STD get<0>(_STD declval<_Other>())), _Ty1>,
295+
is_convertible<decltype(_STD get<1>(_STD declval<_Other>())), _Ty2>>)
296+
pair(_Other&& _Right) noexcept(is_nothrow_constructible_v<_Ty1, decltype(_STD get<0>(_STD declval<_Other>()))>&&
297+
is_nothrow_constructible_v<_Ty2, decltype(_STD get<1>(_STD declval<_Other>()))>) // strengthened
298+
: first(_STD get<0>(_STD forward<_Other>(_Right))), second(_STD get<1>(_STD forward<_Other>(_Right))) {
299+
}
300+
#endif // __cpp_lib_concepts
210301
#endif // _HAS_CXX23
211302

212303
template <class _Tuple1, class _Tuple2, size_t... _Indexes1, size_t... _Indexes2>
@@ -318,6 +409,32 @@ struct pair { // store a pair of values
318409
second = _STD forward<_Other2>(_Right.second);
319410
return *this;
320411
}
412+
413+
#ifdef __cpp_lib_concepts
414+
template <_Pair_like _Other>
415+
requires _Different_from<_Other, pair> && (!_Is_subrange_v<remove_cvref_t<_Other>>)
416+
&& is_assignable_v<_Ty1&, decltype(_STD get<0>(_STD declval<_Other>()))>
417+
&& is_assignable_v<_Ty2&, decltype(_STD get<1>(_STD declval<_Other>()))>
418+
constexpr pair& operator=(_Other&& _Right) noexcept(
419+
is_nothrow_assignable_v<_Ty1&, decltype(_STD get<0>(_STD declval<_Other>()))>&&
420+
is_nothrow_assignable_v<_Ty2&, decltype(_STD get<1>(_STD declval<_Other>()))>) /* strengthened */ {
421+
first = _STD get<0>(_STD forward<_Other>(_Right));
422+
second = _STD get<1>(_STD forward<_Other>(_Right));
423+
return *this;
424+
}
425+
426+
template <_Pair_like _Other>
427+
requires _Different_from<_Other, pair> && (!_Is_subrange_v<remove_cvref_t<_Other>>)
428+
&& is_assignable_v<const _Ty1&, decltype(_STD get<0>(_STD declval<_Other>()))>
429+
&& is_assignable_v<const _Ty2&, decltype(_STD get<1>(_STD declval<_Other>()))>
430+
constexpr const pair& operator=(_Other&& _Right) const noexcept(
431+
is_nothrow_assignable_v<const _Ty1&, decltype(_STD get<0>(_STD declval<_Other>()))>&&
432+
is_nothrow_assignable_v<const _Ty2&, decltype(_STD get<1>(_STD declval<_Other>()))>) /* strengthened */ {
433+
first = _STD get<0>(_STD forward<_Other>(_Right));
434+
second = _STD get<1>(_STD forward<_Other>(_Right));
435+
return *this;
436+
}
437+
#endif // __cpp_lib_concepts
321438
#endif // _HAS_CXX23
322439

323440
_CONSTEXPR20 void swap(pair& _Right) noexcept(
@@ -469,9 +586,6 @@ namespace _CXX20_DEPRECATE_REL_OPS rel_ops {
469586
}
470587
} // namespace _CXX20_DEPRECATE_REL_OPS rel_ops
471588

472-
_EXPORT_STD template <class _Tuple>
473-
struct tuple_size;
474-
475589
template <class _Tuple, class = void>
476590
struct _Tuple_size_sfinae {}; // selected when tuple_size<_Tuple>::value isn't well-formed
477591

@@ -488,12 +602,6 @@ struct _CXX20_DEPRECATE_VOLATILE tuple_size<volatile _Tuple> : _Tuple_size_sfina
488602
template <class _Tuple>
489603
struct _CXX20_DEPRECATE_VOLATILE tuple_size<const volatile _Tuple> : _Tuple_size_sfinae<_Tuple> {}; // ignore cv
490604

491-
_EXPORT_STD template <class _Ty>
492-
_INLINE_VAR constexpr size_t tuple_size_v = tuple_size<_Ty>::value;
493-
494-
_EXPORT_STD template <size_t _Index, class _Tuple>
495-
struct tuple_element;
496-
497605
template <size_t _Index, class _Tuple>
498606
struct _MSVC_KNOWN_SEMANTICS tuple_element<_Index, const _Tuple> : tuple_element<_Index, _Tuple> {
499607
using _Mybase = tuple_element<_Index, _Tuple>;
@@ -514,12 +622,6 @@ struct _CXX20_DEPRECATE_VOLATILE _MSVC_KNOWN_SEMANTICS tuple_element<_Index, con
514622
using type = add_cv_t<typename _Mybase::type>;
515623
};
516624

517-
_EXPORT_STD template <size_t _Index, class _Tuple>
518-
using tuple_element_t = typename tuple_element<_Index, _Tuple>::type;
519-
520-
_EXPORT_STD template <class _Ty, size_t _Size>
521-
class array;
522-
523625
template <class _Ty, size_t _Size>
524626
struct tuple_size<array<_Ty, _Size>> : integral_constant<size_t, _Size> {}; // size of array
525627

stl/inc/xutility

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,9 +1755,6 @@ _NODISCARD constexpr const _Elem* data(initializer_list<_Elem> _Ilist) noexcept
17551755
}
17561756

17571757
#ifdef __cpp_lib_concepts
1758-
template <class _Ty1, class _Ty2>
1759-
concept _Different_from = (!same_as<remove_cvref_t<_Ty1>, remove_cvref_t<_Ty2>>);
1760-
17611758
#if _HAS_CXX23
17621759
_EXPORT_STD template <indirectly_readable _Ty>
17631760
using iter_const_reference_t = common_reference_t<const iter_value_t<_Ty>&&, iter_reference_t<_Ty>>;

stl/inc/yvals_core.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@
322322
// P2077R3 Heterogeneous Erasure Overloads For Associative Containers
323323
// P2136R3 invoke_r()
324324
// P2165R4 Compatibility Between tuple, pair, And tuple-like Objects
325-
// (changes to views::zip only)
325+
// (changes to views::zip and pair only)
326326
// P2166R1 Prohibiting basic_string And basic_string_view Construction From nullptr
327327
// P2186R2 Removing Garbage Collection Support
328328
// P2273R3 constexpr unique_ptr

tests/std/test.lst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,7 @@ tests\P1899R3_views_stride_death
551551
tests\P1951R1_default_arguments_pair_forward_ctor
552552
tests\P2136R3_invoke_r
553553
tests\P2162R2_std_visit_for_derived_classes_from_variant
554+
tests\P2165R4_tuple_like_pair
554555
tests\P2231R1_complete_constexpr_optional_variant
555556
tests\P2273R3_constexpr_unique_ptr
556557
tests\P2278R4_basic_const_iterator
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3+
4+
RUNALL_INCLUDE ..\concepts_latest_matrix.lst

0 commit comments

Comments
 (0)