diff --git a/stl/inc/xutility b/stl/inc/xutility index a8f41b14b5..9d455e5378 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(); 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..fe9ad49845 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,44 @@ 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>(const 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(CanGet, 0>); + STATIC_ASSERT(CanGet, 1>); + STATIC_ASSERT(!CanGet, 2>); + + 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