From 61eff7092298fda830afb7009fab3585763764eb Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Thu, 15 Dec 2022 22:15:25 +0100 Subject: [PATCH 01/41] Add feature test macro --- stl/inc/yvals_core.h | 2 +- .../test.compile.pass.cpp | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index cb76b2081d..61acfccfe3 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -322,7 +322,6 @@ // P2077R3 Heterogeneous Erasure Overloads For Associative Containers // P2136R3 invoke_r() // P2165R4 Compatibility Between tuple, pair, And tuple-like Objects -// (changes to views::zip and pair only) // P2166R1 Prohibiting basic_string And basic_string_view Construction From nullptr // P2186R2 Removing Garbage Collection Support // P2273R3 constexpr unique_ptr @@ -1709,6 +1708,7 @@ _EMIT_STL_ERROR(STL1004, "C++98 unexpected() is incompatible with C++23 unexpect #define __cpp_lib_ranges_starts_ends_with 202106L #define __cpp_lib_ranges_stride 202207L #define __cpp_lib_ranges_to_container 202202L +#define __cpp_lib_tuple_like 202207L #endif // __cpp_lib_concepts #define __cpp_lib_spanstream 202106L diff --git a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp index dbb1d9fdfa..69bb48b239 100644 --- a/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp +++ b/tests/std/tests/VSO_0157762_feature_test_macros/test.compile.pass.cpp @@ -2156,6 +2156,20 @@ STATIC_ASSERT(__cpp_lib_transparent_operators == 201510L); STATIC_ASSERT(__cpp_lib_tuple_element_t == 201402L); #endif +#if _HAS_CXX23 && defined(__cpp_lib_concepts) // TRANSITION, GH-395 +#ifndef __cpp_lib_tuple_like +#error __cpp_lib_tuple_like is not defined +#elif __cpp_lib_tuple_like != 202207L +#error __cpp_lib_tuple_like is not 202207L +#else +STATIC_ASSERT(__cpp_lib_tuple_like == 202207L); +#endif +#else +#ifdef __cpp_lib_tuple_like +#error __cpp_lib_tuple_like is defined +#endif +#endif + #ifndef __cpp_lib_tuples_by_type #error __cpp_lib_tuples_by_type is not defined #elif __cpp_lib_tuples_by_type != 201304L From dee5c280768648c5b98e00c09dbacfe52a8a1d6e Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 16 Dec 2022 02:08:46 +0100 Subject: [PATCH 02/41] Apply changes from `range.subrange` --- stl/inc/xutility | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 235fd627b3..083c374808 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -3617,6 +3617,7 @@ 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; @@ -3626,10 +3627,14 @@ namespace ranges { { _STD get<0>(__t) } -> convertible_to&>; { _STD get<1>(__t) } -> convertible_to&>; }; +#endif // !_HAS_CXX23 template - concept _Pair_like_convertible_from = !range<_Ty> && _Pair_like<_Ty> - && constructible_from<_Ty, _First, _Second> + concept _Pair_like_convertible_from = +#if _HAS_CXX23 + !is_reference_v<_Ty> && +#endif // _HAS_CXX23 + !range<_Ty> && _Pair_like<_Ty> && constructible_from<_Ty, _First, _Second> && _Convertible_to_non_slicing<_First, tuple_element_t<0, _Ty>> && convertible_to<_Second, tuple_element_t<1, _Ty>>; // clang-format on From 079cc4f7f358bf3faf5e2ea968535397e1f325ee Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 16 Dec 2022 02:09:08 +0100 Subject: [PATCH 03/41] Apply changes from `range.elements.view` --- stl/inc/ranges | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index f163e8d799..f2395a8f5e 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -5467,13 +5467,17 @@ namespace ranges { #endif // _HAS_CXX23 template - concept _Has_tuple_element = // + concept _Has_tuple_element = +#if _HAS_CXX23 + _Tuple_like<_Tuple> && _Index < tuple_size_v<_Tuple>; +#else // ^^^ C++23 / C++20 vvv requires(_Tuple __t) { typename tuple_size<_Tuple>::type; requires _Index < tuple_size_v<_Tuple>; typename tuple_element_t<_Index, _Tuple>; { _STD get<_Index>(__t) } -> convertible_to&>; }; +#endif // C++20 template concept _Returnable_element = is_reference_v<_Tuple> || move_constructible>; From 4394897d090197695423ba8c035002690b99647a Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 16 Dec 2022 03:07:48 +0100 Subject: [PATCH 04/41] Apply changes from `associative.general` --- stl/inc/xutility | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 083c374808..310e998dd2 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -1099,14 +1099,30 @@ struct _Is_allocator<_Ty, void_t -using _Guide_key_t = remove_const_t::value_type::first_type>; +using _Guide_key_t = +#if _HAS_CXX23 + tuple_element_t<0, typename iterator_traits<_Iter>::value_type>; +#else // ^^^ C++23 / C++20 vvv + remove_const_t::value_type::first_type>; +#endif // C++20 template -using _Guide_val_t = typename iterator_traits<_Iter>::value_type::second_type; +using _Guide_val_t = +#if _HAS_CXX23 + tuple_element_t<1, typename iterator_traits<_Iter>::value_type>; +#else // ^^^ C++23 / C++20 vvv + typename iterator_traits<_Iter>::value_type::second_type; +#endif // C++20 template -using _Guide_pair_t = pair::value_type::first_type>, - typename iterator_traits<_Iter>::value_type::second_type>; +using _Guide_pair_t = +#if _HAS_CXX23 + pair::value_type>>, + tuple_element_t<1, typename iterator_traits<_Iter>::value_type>>; +#else // ^^^ C++23 / C++20 vvv + pair::value_type::first_type>, + typename iterator_traits<_Iter>::value_type::second_type>; +#endif // C++20 _EXPORT_STD template struct is_execution_policy : false_type {}; From 2f176921e021c0ca7ec81cf628abe5106286a343 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Fri, 16 Dec 2022 16:29:22 +0100 Subject: [PATCH 05/41] Implement `basic_common_reference` and `common_type` for `tuple-like` types --- stl/inc/tuple | 53 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/stl/inc/tuple b/stl/inc/tuple index cef9e93330..7251b36e18 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -888,19 +888,52 @@ _NODISCARD constexpr _Ty make_from_tuple(_Tuple&& _Tpl) { // construct _Ty from template struct uses_allocator, _Alloc> : true_type {}; // true_type if container allocator enabled -#ifdef __cpp_lib_concepts -template class _TQual, template class _UQual> - requires requires { typename tuple, _UQual<_UTypes>>...>; } -struct basic_common_reference, tuple<_UTypes...>, _TQual, _UQual> { - using type = tuple, _UQual<_UTypes>>...>; +#if _HAS_CXX23 && defined(__cpp_lib_concepts) +template <_Tuple_like _TTuple, _Tuple_like _UTuple, template class _TQual, template class _UQual, + typename _Indices = make_index_sequence>> +struct _Tuple_like_common_reference {}; + +template class _TQual, template class _UQual, + size_t... _Indices> + requires requires { + typename tuple>, + _UQual>>...>; + } +struct _Tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual, index_sequence<_Indices...>> { + using type = tuple< + common_reference_t<_TQual>, _UQual>>...>; }; -template - requires requires { typename tuple...>; } -struct common_type, tuple<_UTypes...>> { - using type = tuple...>; +template <_Tuple_like _TTuple, _Tuple_like _UTuple, template class _TQual, template class _UQual> + requires (_Is_specialization_v<_TTuple, tuple> || _Is_specialization_v<_UTuple, tuple>) + && is_same_v<_TTuple, decay_t<_TTuple>> && is_same_v<_UTuple, decay_t<_UTuple>> + && (tuple_size_v<_TTuple> == tuple_size_v<_UTuple>) + && requires { typename _Tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual>::type; } +struct basic_common_reference<_TTuple, _UTuple, _TQual, _UQual> { + using type = typename _Tuple_like_common_reference<_TTuple, _UTuple, _TQual, _UQual>::type; }; -#endif // __cpp_lib_concepts + +template <_Tuple_like _TTuple, _Tuple_like _UTuple, typename _Indices = make_index_sequence>> +struct _Tuple_like_common_type {}; + +template + requires requires { + typename tuple< + common_type_t, tuple_element_t<_Indices, _UTuple>>...>; + } +struct _Tuple_like_common_type<_TTuple, _UTuple, index_sequence<_Indices...>> { + using type = tuple, tuple_element_t<_Indices, _UTuple>>...>; +}; + +template <_Tuple_like _TTuple, _Tuple_like _UTuple> + requires (_Is_specialization_v<_TTuple, tuple> || _Is_specialization_v<_UTuple, tuple>) + && is_same_v<_TTuple, decay_t<_TTuple>> && is_same_v<_UTuple, decay_t<_UTuple>> + && (tuple_size_v<_TTuple> == tuple_size_v<_UTuple>) + && requires { typename _Tuple_like_common_type<_TTuple, _UTuple>::type; } +struct common_type<_TTuple, _UTuple> { + using type = typename _Tuple_like_common_type<_TTuple, _UTuple>::type; +}; +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) #if _HAS_TR1_NAMESPACE namespace _DEPRECATE_TR1_NAMESPACE tr1 { From 14b2efc6a7273770e2a67ddf9eb58d1d05f8301f Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 23 Jan 2023 16:37:06 +0100 Subject: [PATCH 06/41] Implement `common_reference` and `common_type` tests --- tests/std/test.lst | 2 + .../env.lst | 4 + .../test.compile.pass.cpp | 92 +++++++++++++++++++ .../P2165R4_tuple_like_common_type/env.lst | 4 + .../test.compile.pass.cpp | 85 +++++++++++++++++ 5 files changed, 187 insertions(+) create mode 100644 tests/std/tests/P2165R4_tuple_like_common_reference/env.lst create mode 100644 tests/std/tests/P2165R4_tuple_like_common_reference/test.compile.pass.cpp create mode 100644 tests/std/tests/P2165R4_tuple_like_common_type/env.lst create mode 100644 tests/std/tests/P2165R4_tuple_like_common_type/test.compile.pass.cpp diff --git a/tests/std/test.lst b/tests/std/test.lst index 56a9393744..ddffe4b006 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -551,6 +551,8 @@ tests\P1899R3_views_stride_death tests\P1951R1_default_arguments_pair_forward_ctor tests\P2136R3_invoke_r tests\P2162R2_std_visit_for_derived_classes_from_variant +tests\P2165R4_tuple_like_common_reference +tests\P2165R4_tuple_like_common_type tests\P2165R4_tuple_like_pair tests\P2231R1_complete_constexpr_optional_variant tests\P2273R3_constexpr_unique_ptr diff --git a/tests/std/tests/P2165R4_tuple_like_common_reference/env.lst b/tests/std/tests/P2165R4_tuple_like_common_reference/env.lst new file mode 100644 index 0000000000..18e2d7c71e --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_common_reference/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2165R4_tuple_like_common_reference/test.compile.pass.cpp b/tests/std/tests/P2165R4_tuple_like_common_reference/test.compile.pass.cpp new file mode 100644 index 0000000000..2084f61923 --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_common_reference/test.compile.pass.cpp @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +using namespace std; +using ranges::subrange; + +template +concept CanCommonReference = requires { typename common_reference::type; }; + +template + requires CanCommonReference +constexpr bool test_common_reference = + same_as, Expected> && same_as, Expected>; + +struct Sentinel { + bool operator==(const auto&) const; // not defined + operator unreachable_sentinel_t() const; // not defined +}; + +template <> +struct std::common_type { + using type = unreachable_sentinel_t; +}; + +template <> +struct std::common_type { + using type = unreachable_sentinel_t; +}; + +static_assert(test_common_reference); + +// Test common_reference +static_assert(test_common_reference, tuple<>, tuple<>>); +static_assert(test_common_reference, tuple, tuple>); +static_assert(test_common_reference, tuple, tuple>); +static_assert(test_common_reference, tuple, tuple>); +static_assert(test_common_reference, tuple, tuple>); + +// Test common_reference +static_assert(test_common_reference&, tuple<>&&, const tuple<>&>); +static_assert( + test_common_reference&, volatile tuple&, const volatile tuple&>); +static_assert(test_common_reference&, + const tuple, tuple>); + +// Test common_reference, tuple-like is pair +static_assert(test_common_reference, pair, tuple>); +static_assert(test_common_reference, pair, tuple>); +static_assert( + test_common_reference, pair, tuple>); +static_assert(test_common_reference, pair, tuple>); + +// Test common_reference, tuple-like is pair +static_assert(test_common_reference&, pair&, tuple>); +static_assert( + test_common_reference&, const pair&, tuple>); +static_assert(test_common_reference, const pair&, + tuple>); + +// Test common_reference, tuple-like is array +static_assert(test_common_reference, array, tuple<>>); +static_assert(test_common_reference, array, tuple>); +static_assert(test_common_reference, array, tuple>); +static_assert(test_common_reference, array, tuple>); +static_assert(test_common_reference, array, tuple>); + +// Test common_reference, tuple-like is array +static_assert(test_common_reference&, array, tuple<>>); +static_assert(test_common_reference&, array&, tuple>); +static_assert(test_common_reference&&, array&, tuple>); + +// Test common_reference, tuple-like is ranges::subrange +static_assert(test_common_reference, subrange, tuple>); +static_assert( + test_common_reference, subrange, tuple>); +static_assert(test_common_reference, subrange, + tuple>); +static_assert(test_common_reference, subrange, + tuple>); + +// Test common_reference, tuple-like is ranges::subrange +static_assert(test_common_reference&&, const subrange, tuple>); +static_assert( + test_common_reference&, subrange, tuple>); + +int main() {} // COMPILE-ONLY diff --git a/tests/std/tests/P2165R4_tuple_like_common_type/env.lst b/tests/std/tests/P2165R4_tuple_like_common_type/env.lst new file mode 100644 index 0000000000..18e2d7c71e --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_common_type/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2165R4_tuple_like_common_type/test.compile.pass.cpp b/tests/std/tests/P2165R4_tuple_like_common_type/test.compile.pass.cpp new file mode 100644 index 0000000000..499515f046 --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_common_type/test.compile.pass.cpp @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +using namespace std; +using ranges::subrange; + +template +concept CanCommonType = requires { typename common_type::type; }; + +template + requires CanCommonType +inline constexpr bool test_common_type = + same_as, Expected> && same_as, Expected>; + +struct Sentinel { + bool operator==(const auto&) const; // not defined + operator unreachable_sentinel_t() const; // not defined +}; + +template <> +struct std::common_type { + using type = unreachable_sentinel_t; +}; + +template <> +struct std::common_type { + using type = unreachable_sentinel_t; +}; + +static_assert(test_common_type); + +// Test common_type +static_assert(test_common_type, tuple<>, tuple<>>); +static_assert(test_common_type, tuple, tuple>); +static_assert(test_common_type, tuple, tuple>); +static_assert(test_common_type, tuple, tuple>); +static_assert(test_common_type, tuple, tuple>); + +// Test common_reference +static_assert(test_common_type&, tuple<>&&, tuple<>>); +static_assert(test_common_type&, const tuple&&, tuple>); +static_assert(test_common_type&, tuple, tuple>); +static_assert(test_common_type&, tuple, tuple>); + +// Test common_type, tuple-like is pair +static_assert(test_common_type, pair, tuple>); +static_assert(test_common_type, pair, tuple>); +static_assert(test_common_type, pair, tuple>); +static_assert(test_common_type, pair, tuple>); + +// Test common_type, tuple-like is pair +static_assert(test_common_type&&, volatile pair&, tuple>); +static_assert(test_common_type&&, const pair&&, tuple>); + +// Test common_type, tuple-like is array +static_assert(test_common_type, array, tuple<>>); +static_assert(test_common_type, array, tuple>); +static_assert(test_common_type, array, tuple>); +static_assert(test_common_type, array, tuple>); +static_assert(test_common_type, array, tuple>); + +// Test common_type, tuple-like is array +static_assert(test_common_type&&, volatile array&, tuple<>>); +static_assert(test_common_type&, volatile array&&, tuple>); + +// Test common_type, tuple-like is ranges::subrange +static_assert(test_common_type, subrange, tuple>); +static_assert(test_common_type, subrange, tuple>); +static_assert(test_common_type, subrange, + tuple>); +static_assert(test_common_type, subrange, + tuple>); + +// Test common_type, tuple-like is ranges::subrange +static_assert(test_common_type&, volatile subrange&&, tuple>); +static_assert(test_common_type&, const subrange&&, + tuple>); + +int main() {} // COMPILE-ONLY From 8ab8d8409c740b5946798d1d021285e54dbad86d Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 23 Jan 2023 19:11:46 +0100 Subject: [PATCH 07/41] Remove useless forward declarations of `get(tuple)` function --- stl/inc/xutility | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 310e998dd2..99d7587f28 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -3611,17 +3611,6 @@ namespace ranges { }; } // namespace ranges -// These declarations must be visible to qualified name lookup for _STD get in _Pair_like below, even if hasn't -// yet been included. -_EXPORT_STD template -_NODISCARD constexpr tuple_element_t<_Index, tuple<_Types...>>& get(tuple<_Types...>& _Tuple) noexcept; -_EXPORT_STD template -_NODISCARD constexpr const tuple_element_t<_Index, tuple<_Types...>>& get(const tuple<_Types...>& _Tuple) noexcept; -_EXPORT_STD template -_NODISCARD constexpr tuple_element_t<_Index, tuple<_Types...>>&& get(tuple<_Types...>&& _Tuple) noexcept; -_EXPORT_STD template -_NODISCARD constexpr const tuple_element_t<_Index, tuple<_Types...>>&& get(const tuple<_Types...>&& _Tuple) noexcept; - namespace ranges { // clang-format off template From f812a39cae7635848d37d2e6c5751fedc56ffe92 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Mon, 23 Jan 2023 22:25:45 +0100 Subject: [PATCH 08/41] Test changes to `[associative.general]` Also fix `_Guide_key_t` --- stl/inc/xutility | 2 +- tests/std/tests/P0433R2_deduction_guides/test.cpp | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 99d7587f28..26dc7b9f2f 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -1101,7 +1101,7 @@ struct _Is_allocator<_Ty, void_t using _Guide_key_t = #if _HAS_CXX23 - tuple_element_t<0, typename iterator_traits<_Iter>::value_type>; + remove_const_t::value_type>>; #else // ^^^ C++23 / C++20 vvv remove_const_t::value_type::first_type>; #endif // C++20 diff --git a/tests/std/tests/P0433R2_deduction_guides/test.cpp b/tests/std/tests/P0433R2_deduction_guides/test.cpp index 8b99de5f0b..e943019850 100644 --- a/tests/std/tests/P0433R2_deduction_guides/test.cpp +++ b/tests/std/tests/P0433R2_deduction_guides/test.cpp @@ -651,6 +651,20 @@ void test_map_or_multimap() { static_assert(is_same_v>); static_assert(is_same_v>>); static_assert(is_same_v, MyAlloc>>); + + { // Verify changes from P2165R4 + using TupleIter = tuple*; + static_assert(is_same_v>); + + using PairIter = pair*; + static_assert(is_same_v>); + + using ArrayIter = array*; + static_assert(is_same_v>); + + using SubrangeIter = ranges::subrange*; + static_assert(is_same_v>); + } #endif // _HAS_CXX23 && defined(__cpp_lib_concepts) } From e19cfea374f613feca6e40788ef70af8018c8818 Mon Sep 17 00:00:00 2001 From: Jakub Mazurkiewicz Date: Sun, 29 Jan 2023 03:08:10 +0100 Subject: [PATCH 09/41] New `tuple` members + tests --- stl/inc/tuple | 99 +++++++ tests/std/test.lst | 1 + .../P2165R4_tuple_like_tuple_members/env.lst | 4 + .../P2165R4_tuple_like_tuple_members/test.cpp | 280 ++++++++++++++++++ 4 files changed, 384 insertions(+) create mode 100644 tests/std/tests/P2165R4_tuple_like_tuple_members/env.lst create mode 100644 tests/std/tests/P2165R4_tuple_like_tuple_members/test.cpp diff --git a/stl/inc/tuple b/stl/inc/tuple index 7251b36e18..ebccf3c832 100644 --- a/stl/inc/tuple +++ b/stl/inc/tuple @@ -186,12 +186,24 @@ public: constexpr tuple(const tuple&) noexcept /* strengthened */ {} // TRANSITION, ABI: should be defaulted +#if _HAS_CXX23 && defined(__cpp_lib_concepts) + template <_Tuple_like _Other> + requires _Different_from<_Other, tuple> && (tuple_size_v> == 0) + constexpr tuple(_Other&&) noexcept /* strengthened */ {} +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) + template _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc&) noexcept /* strengthened */ {} template _CONSTEXPR20 tuple(allocator_arg_t, const _Alloc&, const tuple&) noexcept /* strengthened */ {} +#if _HAS_CXX23 && defined(__cpp_lib_concepts) + template + requires _Different_from<_Other, tuple> && (tuple_size_v> == 0) + constexpr tuple(allocator_arg_t, const _Alloc&, _Other&&) noexcept /* strengthened */ {} +#endif // _HAS_CXX23 && defined(__cpp_lib_concepts) + template , int> = 0> constexpr tuple(_Tag) noexcept /* strengthened */ {} @@ -203,6 +215,20 @@ public: constexpr const tuple& operator=(const tuple&) const noexcept /* strengthened */ { return *this; } + +#if defined(__cpp_lib_concepts) + template <_Tuple_like _Other> + requires _Different_from<_Other, tuple> && (tuple_size_v> == 0) + constexpr tuple& operator=(_Other&&) noexcept /* strengthened */ { + return *this; + } + + template <_Tuple_like _Other> + requires _Different_from<_Other, tuple> && (tuple_size_v> == 0) + constexpr const tuple& operator=(_Other&&) const noexcept /* strengthened */ { + return *this; + } +#endif // defined(__cpp_lib_concepts) #endif // _HAS_CXX23 _CONSTEXPR20 void swap(tuple&) noexcept {} @@ -343,6 +369,32 @@ public: tuple(const pair<_First, _Second>&& _Right) noexcept( _Tuple_nothrow_constructible_v) // strengthened : tuple(_Unpack_tuple_t{}, _STD move(_Right)) {} + +#ifdef __cpp_lib_concepts + template > + static constexpr bool _Can_construct_from_tuple_like_v = false; + + template <_Tuple_like _Other, size_t... _Indices> + static constexpr bool _Can_construct_from_tuple_like_v<_Other, index_sequence<_Indices...>> = + _Different_from<_Other, tuple> && !_Is_subrange_v> + && 1 + sizeof...(_Rest) == tuple_size_v> + && (is_constructible_v<_This, decltype(_STD get<0>(_STD declval<_Other>()))> && ... + && is_constructible_v<_Rest, decltype(_STD get<_Indices + 1>(_STD declval<_Other>()))>) // + &&(sizeof...(_Rest) != 0 || (!is_convertible_v<_Other, _This> && !is_constructible_v<_This, _Other>) ); + + template > + static constexpr bool _Is_tuple_like_constructor_explicit_v = false; + + template <_Tuple_like _Other, size_t... _Indices> + static constexpr bool _Is_tuple_like_constructor_explicit_v<_Other, index_sequence<_Indices...>> = + !(is_convertible_v(_STD declval<_Other>())), _This> && ... + && is_convertible_v(_STD declval<_Other>())), _Rest>); + + template <_Tuple_like _Other> + requires _Can_construct_from_tuple_like_v<_Other> + constexpr explicit(_Is_tuple_like_constructor_explicit_v<_Other>) tuple(_Other&& _Right) + : tuple(_Unpack_tuple_t{}, _STD forward<_Other>(_Right)) {} +#endif // __cpp_lib_concepts #endif // _HAS_CXX23 template ) tuple(allocator_arg_t, const _Alloc& _Al, const pair<_First, _Second>&& _Right) : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD move(_Right)) {} + +#ifdef __cpp_lib_concepts + template + requires _Can_construct_from_tuple_like_v<_Other> + constexpr explicit(_Is_tuple_like_constructor_explicit_v<_Other>) + tuple(allocator_arg_t, const _Alloc& _Al, _Other&& _Right) + : tuple(_Alloc_unpack_tuple_t{}, _Al, _STD forward<_Other>(_Right)) {} +#endif // __cpp_lib_concepts #endif // _HAS_CXX23 tuple& operator=(const volatile tuple&) = delete; @@ -570,6 +630,45 @@ public: _Get_rest()._Myfirst._Val = _STD forward<_Second>(_Right.second); return *this; } + +#ifdef __cpp_lib_concepts + template > + static constexpr bool _Can_assign_from_tuple_like_v = false; + + template + static constexpr bool _Can_assign_from_tuple_like_v<_Const_assignment, _Other, index_sequence<_Indices...>> = + _Different_from<_Other, tuple> && !_Is_subrange_v> + && 1 + sizeof...(_Rest) == tuple_size_v> + && (is_assignable_v, + decltype(_STD get<0>(_STD declval<_Other>()))> + && ... && // + is_assignable_v, + decltype(_STD get<_Indices + 1>(_STD declval<_Other>()))>); + + template <_Tuple_like _Other, size_t... _Indices> + constexpr void _Assign_tuple_like(_Other&& _Right, index_sequence<_Indices...>) { + ((_STD get<_Indices>(*this) = _STD get<_Indices>(_STD forward<_Other>(_Right))), ...); + } + + template <_Tuple_like _Other, size_t... _Indices> + constexpr void _Assign_tuple_like(_Other&& _Right, index_sequence<_Indices...>) const { + ((_STD get<_Indices>(*this) = _STD get<_Indices>(_STD forward<_Other>(_Right))), ...); + } + + template <_Tuple_like _Other> + requires _Can_assign_from_tuple_like_v + constexpr tuple& operator=(_Other&& _Right) { + _Assign_tuple_like(_STD forward<_Other>(_Right), make_index_sequence<1 + sizeof...(_Rest)>{}); + return *this; + } + + template <_Tuple_like _Other> + requires _Can_assign_from_tuple_like_v + constexpr const tuple& operator=(_Other&& _Right) const { + _Assign_tuple_like(_STD forward<_Other>(_Right), make_index_sequence<1 + sizeof...(_Rest)>{}); + return *this; + } +#endif // __cpp_lib_concepts #endif // _HAS_CXX23 _CONSTEXPR20 void swap(tuple& _Right) noexcept( diff --git a/tests/std/test.lst b/tests/std/test.lst index ddffe4b006..bb4d9b0d05 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -554,6 +554,7 @@ tests\P2162R2_std_visit_for_derived_classes_from_variant tests\P2165R4_tuple_like_common_reference tests\P2165R4_tuple_like_common_type tests\P2165R4_tuple_like_pair +tests\P2165R4_tuple_like_tuple_members tests\P2231R1_complete_constexpr_optional_variant tests\P2273R3_constexpr_unique_ptr tests\P2278R4_basic_const_iterator diff --git a/tests/std/tests/P2165R4_tuple_like_tuple_members/env.lst b/tests/std/tests/P2165R4_tuple_like_tuple_members/env.lst new file mode 100644 index 0000000000..18e2d7c71e --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_tuple_members/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2165R4_tuple_like_tuple_members/test.cpp b/tests/std/tests/P2165R4_tuple_like_tuple_members/test.cpp new file mode 100644 index 0000000000..3586750262 --- /dev/null +++ b/tests/std/tests/P2165R4_tuple_like_tuple_members/test.cpp @@ -0,0 +1,280 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +template