From 16592022bab65093d75b6700b1114b052f7cd42e Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Thu, 16 Dec 2021 21:46:59 -0800 Subject: [PATCH 1/2] subrange `get<0>` requires a copyable iterator per LWG-3589. Fixes #2399 --- stl/inc/xutility | 4 +- .../test.compile.pass.cpp | 37 ++++++++++++++++++- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index a8f41b14b5..8ff0e14410 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -3487,7 +3487,7 @@ namespace ranges { // clang-format off template - requires (_Idx < 2) + requires ((_Idx == 0 && copyable<_It>) || _Idx == 1) _NODISCARD constexpr auto get(const subrange<_It, _Se, _Ki>& _Val) { if constexpr (_Idx == 0) { return _Val.begin(); @@ -3497,7 +3497,7 @@ namespace ranges { } template - requires (_Idx < 2) + requires ((_Idx == 0 && copyable<_It>) || _Idx == 1) _NODISCARD constexpr auto get(subrange<_It, _Se, _Ki>&& _Val) { if constexpr (_Idx == 0) { return _Val.begin(); diff --git a/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp b/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp index be0cbaa1d7..f1ff556d15 100644 --- a/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp +++ b/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp @@ -4,8 +4,8 @@ // Covers ranges::view_interface and ranges::subrange #include -#include #include +#include #include #include #include @@ -24,6 +24,7 @@ using std::output_iterator_tag, std::input_iterator_tag, std::forward_iterator_t int main() {} // COMPILE-ONLY void test_LWG_3470() { + // LWG-3470 relaxed the "convertible-to-non-slicing" requirements to allow this non-slicing case int a[] = {1, 2, 3}; int* b[] = {&a[2], &a[0], &a[1]}; [[maybe_unused]] auto c = std::ranges::subrange(b); @@ -1483,3 +1484,37 @@ namespace test_subrange { STATIC_ASSERT(test_tuple>()); STATIC_ASSERT(test_tuple>()); } // namespace test_subrange + +namespace test_lwg_3589 { + // LWG-3589 added a Constraint to std::get<0>(subrange) to require the iterator type to be copyable + template + concept CanGet = requires { + std::get(std::declval()); + }; + + template + concept CanRangesGet = requires { + ranges::get(std::declval()); + }; + + template + constexpr bool test() { + using ranges::subrange; + + STATIC_ASSERT(std::input_iterator); + STATIC_ASSERT(std::sentinel_for); + + STATIC_ASSERT(CanGet, 0> == std::copyable); + STATIC_ASSERT(CanGet, 1>); + STATIC_ASSERT(!CanGet, 2>); + + STATIC_ASSERT(CanRangesGet, 0> == std::copyable); + STATIC_ASSERT(CanRangesGet, 1>); + STATIC_ASSERT(!CanRangesGet, 2>); + + return true; + } + + STATIC_ASSERT(test()); + STATIC_ASSERT(test>, ranges::sentinel_t>>()); +} // namespace test_lwg_3589 From a57013385d13cb8a4e90218165ba65b8eade4c56 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Sat, 18 Dec 2021 11:44:19 -0800 Subject: [PATCH 2/2] Implement LWG-3589 _correctly_ --- stl/inc/xutility | 4 ++-- .../P0896R4_ranges_subrange/test.compile.pass.cpp | 13 ++++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 8ff0e14410..9d455e5378 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -3487,7 +3487,7 @@ namespace ranges { // clang-format off template - requires ((_Idx == 0 && copyable<_It>) || _Idx == 1) + requires ((_Idx == 0 && copyable<_It>) || _Idx == 1) _NODISCARD constexpr auto get(const subrange<_It, _Se, _Ki>& _Val) { if constexpr (_Idx == 0) { return _Val.begin(); @@ -3497,7 +3497,7 @@ namespace ranges { } template - requires ((_Idx == 0 && copyable<_It>) || _Idx == 1) + requires (_Idx < 2) _NODISCARD constexpr auto get(subrange<_It, _Se, _Ki>&& _Val) { if constexpr (_Idx == 0) { return _Val.begin(); diff --git a/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp b/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp index f1ff556d15..fe9ad49845 100644 --- a/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp +++ b/tests/std/tests/P0896R4_ranges_subrange/test.compile.pass.cpp @@ -1486,7 +1486,7 @@ namespace test_subrange { } // namespace test_subrange namespace test_lwg_3589 { - // LWG-3589 added a Constraint to std::get<0>(subrange) to require the iterator type to be copyable + // LWG-3589 added a Constraint to std::get<0>(const subrange&) to require the iterator type to be copyable template concept CanGet = requires { std::get(std::declval()); @@ -1504,17 +1504,24 @@ namespace test_lwg_3589 { STATIC_ASSERT(std::input_iterator); STATIC_ASSERT(std::sentinel_for); - STATIC_ASSERT(CanGet, 0> == std::copyable); + STATIC_ASSERT(CanGet&, 0> == std::copyable); + STATIC_ASSERT(CanGet&, 1>); + STATIC_ASSERT(!CanGet&, 2>); + STATIC_ASSERT(CanGet, 0>); STATIC_ASSERT(CanGet, 1>); STATIC_ASSERT(!CanGet, 2>); - STATIC_ASSERT(CanRangesGet, 0> == std::copyable); + STATIC_ASSERT(CanRangesGet&, 0> == std::copyable); + STATIC_ASSERT(CanRangesGet&, 1>); + STATIC_ASSERT(!CanRangesGet&, 2>); + STATIC_ASSERT(CanRangesGet, 0>); STATIC_ASSERT(CanRangesGet, 1>); STATIC_ASSERT(!CanRangesGet, 2>); return true; } + // Validate with a copyable iterator type, and with a move-only iterator type STATIC_ASSERT(test()); STATIC_ASSERT(test>, ranges::sentinel_t>>()); } // namespace test_lwg_3589