diff --git a/stl/inc/ranges b/stl/inc/ranges index 07b5d1e511d..8317ea26049 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -4706,7 +4706,9 @@ namespace ranges { template concept _Has_tuple_element = #if _HAS_CXX23 - _Tuple_like<_Tuple> && _Index < tuple_size_v<_Tuple>; + _Tuple_like<_Tuple> && _Index < tuple_size_v<_Tuple> && requires(_Tuple __t) { + { _STD get<_Index>(__t) } -> convertible_to&>; + }; #else // ^^^ _HAS_CXX23 / !_HAS_CXX23 vvv requires(_Tuple __t) { typename tuple_size<_Tuple>::type; diff --git a/tests/std/tests/P0896R4_views_elements/test.cpp b/tests/std/tests/P0896R4_views_elements/test.cpp index 96e10edf6fa..6d4d90a1971 100644 --- a/tests/std/tests/P0896R4_views_elements/test.cpp +++ b/tests/std/tests/P0896R4_views_elements/test.cpp @@ -414,6 +414,32 @@ void test_gh_3014() { // COMPILE-ONLY [[maybe_unused]] decltype(as_const(r).begin()) i = r.begin(); // Check 'iterator(iterator i)' } +// LWG-3797 "elements_view insufficiently constrained" +namespace lwg_3797 { + struct Constifier { + template + constexpr const T& operator()(const T& t) const noexcept { + return t; + } + }; + + struct Mover { + template + constexpr remove_reference_t&& operator()(T&& t) const noexcept { + return static_cast&&>(t); + } + }; + + using MoveOnlySubrange = ranges::subrange, test::sentinel>; + static_assert(!CanViewElements>); + static_assert(!CanViewElements{} | views::transform(Constifier{}))>); + static_assert(!CanViewElements{} | views::transform(Mover{}))>); +#if _HAS_CXX23 + static_assert(!CanViewElements{} | views::as_const)>); + static_assert(!CanViewElements{} | views::as_rvalue)>); +#endif // _HAS_CXX23 +} // namespace lwg_3797 + int main() { { // Validate copyable views constexpr span s{some_pairs};