[PATCH] libsdc++: Restore check for validity of std::get for elements_view.
Tomasz Kamiński
tkaminsk@redhat.com
Fri Apr 24 13:25:37 GMT 2026
Resolves LWG3797, "elements_view insufficiently constrained".
When P2165R4 updated __has_tuple_element in C++23 to reuse __tuple_like
concept, it dropped the requirement of validity of get, assuming that for
tuple_like type with size of N, get<I> on lvalue is well-formed for any I < N.
This however does not hold for ranges::subrange (tuple-like of size 2) with
move-only iterator, for which get can only be applied on rvalue. In consequence
constrains allowed instantiating elements_view for range of such subrange,
but instantiating it's iterator lead to hard error from iterator_category
computation.
This patch applies the requirements on validity of get in all standard
modes.
libstdc++-v3/ChangeLog:
* include/std/ranges (__detail::__has_tuple_element): Check
if std::get<_Nm>(__t) returns referenceable type also for C++23
and later.
* testsuite/std/ranges/adaptors/elements.cc: Add test covering
vector of ranges::subrange with move-only iterator.
---
I initially tought that we should backport it, but the only impact of
the issues is you cannot rely on constraint check on views::elements
of such range. Any use of such elements_views remain ill-formed in
all modes.
Testing on x86-64_linux. All *elements* test passed in all standard
modes. OK for trunk when all test passes?
libstdc++-v3/include/std/ranges | 15 ++++++++++-----
.../testsuite/std/ranges/adaptors/elements.cc | 15 +++++++++++++++
2 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges
index 55d3c520ba4..4eb0a1a25bf 100644
--- a/libstdc++-v3/include/std/ranges
+++ b/libstdc++-v3/include/std/ranges
@@ -4354,20 +4354,25 @@ namespace views::__adaptor
namespace __detail
{
-#if __cpp_lib_tuple_like // >= C++23
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 3797. elements_view insufficiently constrained
template<typename _Tp, size_t _Nm>
- concept __has_tuple_element = __tuple_like<_Tp> && _Nm < tuple_size_v<_Tp>;
+ concept __has_tuple_element =
+#if __cpp_lib_tuple_like // >= C++23
+ __tuple_like<_Tp> && _Nm < tuple_size_v<_Tp>
#else
- template<typename _Tp, size_t _Nm>
- concept __has_tuple_element = requires(_Tp __t)
+ requires
{
typename tuple_size<_Tp>::type;
requires _Nm < tuple_size_v<_Tp>;
typename tuple_element_t<_Nm, _Tp>;
+ }
+#endif
+ && requires(_Tp __t)
+ {
{ std::get<_Nm>(__t) }
-> convertible_to<const tuple_element_t<_Nm, _Tp>&>;
};
-#endif
template<typename _Tp, size_t _Nm>
concept __returnable_element
diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc
index 5237d787e7b..1b15f79c5be 100644
--- a/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc
+++ b/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc
@@ -27,6 +27,21 @@
namespace ranges = std::ranges;
namespace views = ranges::views;
+template<size_t N, typename Rg>
+concept can_elements = requires (Rg&& rg)
+{ views::elements<0>(rg); };
+
+static_assert( !can_elements<0, std::vector<int>> );
+static_assert( can_elements<0, std::tuple<int>[4]> );
+static_assert( can_elements<1, std::vector<std::pair<int, int>>> );
+
+using move_only_iter_range = __gnu_test::test_input_range_nocopy<int>;
+using move_only_iter_subrange = ranges::subrange<
+ ranges::iterator_t<move_only_iter_range>,
+ ranges::sentinel_t<move_only_iter_range>>;
+static_assert( can_elements<0, std::vector<ranges::subrange<int*>>> );
+static_assert( !can_elements<0, std::vector<move_only_iter_subrange>> );
+
void
test01()
{
--
2.53.0
More information about the Libstdc++
mailing list