[PATCH] libstdc++: implement P3052R2 view_interface::at()

Yuao Ma addr2line@gmail.com
Thu Sep 17 13:15:34 GMT 2026


Hi all,

This patch implements the C++29 paper P3052R2, which adds _at_ to
view_interface. The implementation is straightforward and similar to
span::at.

Built and tested on x86_64-linux, ok for trunk?

Thanks,
Yuao
-------------- next part --------------
From 86863536e710326226596a98a79054626a0ab783 Mon Sep 17 00:00:00 2001
From: Yuao Ma <c8ef@outlook.com>
Date: Thu, 17 Sep 2026 21:10:39 +0800
Subject: [PATCH] libstdc++: implement P3052R2 view_interface::at()

libstdc++-v3/ChangeLog:

	* include/bits/ranges_util.h (view_interface::at): Define.
	* include/bits/version.def: Define view_interface.
	* include/bits/version.h: Regenerate.
	* testsuite/std/ranges/p3052.cc: New test.
---
 libstdc++-v3/include/bits/ranges_util.h    | 27 +++++++++++
 libstdc++-v3/include/bits/version.def      |  8 ++++
 libstdc++-v3/include/bits/version.h        | 10 ++++
 libstdc++-v3/testsuite/std/ranges/p3052.cc | 53 ++++++++++++++++++++++
 4 files changed, 98 insertions(+)
 create mode 100644 libstdc++-v3/testsuite/std/ranges/p3052.cc

diff --git a/libstdc++-v3/include/bits/ranges_util.h b/libstdc++-v3/include/bits/ranges_util.h
index 423767f00fc..ae803461801 100644
--- a/libstdc++-v3/include/bits/ranges_util.h
+++ b/libstdc++-v3/include/bits/ranges_util.h
@@ -39,6 +39,13 @@
 # include <bits/stl_pair.h> // __pair_like, __is_tuple_like_v
 #endif
 
+#define __glibcxx_want_view_interface
+#include <bits/version.h>
+
+#if __cpp_lib_view_interface // >= C++29
+# include <bits/stdexcept_throw.h>
+#endif
+
 #ifdef __glibcxx_ranges
 namespace std _GLIBCXX_VISIBILITY(default)
 {
@@ -199,6 +206,26 @@ namespace ranges
 	operator[](range_difference_t<_Range> __n) const
 	{ return ranges::begin(_M_derived())[__n]; }
 
+#if __cpp_lib_view_interface // >= C++29
+      template<random_access_range _Range = _Derived>
+	constexpr decltype(auto)
+	at(range_difference_t<_Range> __n) requires sized_range<_Range>
+	{
+	  if (__n < 0 || __n >= ranges::distance(_M_derived()))
+	    std::__throw_out_of_range("view_interface::at");
+	  return (*this)[__n];
+	}
+
+      template<random_access_range _Range = const _Derived>
+	constexpr decltype(auto)
+	at(range_difference_t<_Range> __n) const requires sized_range<_Range>
+	{
+	  if (__n < 0 || __n >= ranges::distance(_M_derived()))
+	    std::__throw_out_of_range("view_interface::at");
+	  return (*this)[__n];
+	}
+#endif
+
 #if __cplusplus > 202002L
       constexpr auto
       cbegin() requires input_range<_Derived>
diff --git a/libstdc++-v3/include/bits/version.def b/libstdc++-v3/include/bits/version.def
index 9c523581c65..17589685f90 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -2164,6 +2164,14 @@ ftms = {
   };
 };
 
+ftms = {
+  name = view_interface;
+  values = {
+    v = 202606;
+    cxxmin = 29;
+  };
+};
+
 ftms = {
   name = observable_checkpoint;
   values = {
diff --git a/libstdc++-v3/include/bits/version.h b/libstdc++-v3/include/bits/version.h
index e0003054af6..4df6a648323 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2391,6 +2391,16 @@
 #endif /* !defined(__cpp_lib_unreachable) */
 #undef __glibcxx_want_unreachable
 
+#if !defined(__cpp_lib_view_interface)
+# if (__cplusplus >  202603L)
+#  define __glibcxx_view_interface 202606L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_view_interface)
+#   define __cpp_lib_view_interface 202606L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_view_interface) */
+#undef __glibcxx_want_view_interface
+
 #if !defined(__cpp_lib_observable_checkpoint)
 # if (__cplusplus >  202302L) && (__has_builtin(__builtin_observable_checkpoint))
 #  define __glibcxx_observable_checkpoint 202506L
diff --git a/libstdc++-v3/testsuite/std/ranges/p3052.cc b/libstdc++-v3/testsuite/std/ranges/p3052.cc
new file mode 100644
index 00000000000..433a37dc5df
--- /dev/null
+++ b/libstdc++-v3/testsuite/std/ranges/p3052.cc
@@ -0,0 +1,53 @@
+// { dg-do run { target c++29 } }
+
+#include <testsuite_hooks.h>
+
+#include <ranges>
+#include <stdexcept>
+
+struct v1 : std::ranges::view_interface<v1> {
+  int* ptr;
+  std::size_t sz;
+
+  constexpr v1(int* p, std::size_t n) : ptr(p), sz(n) {}
+
+  constexpr int* begin() const noexcept { return ptr; }
+  constexpr int* end() const noexcept { return ptr + sz; }
+};
+
+void test01() {
+  int x[2]{0, 1};
+  v1 v(x, 2);
+  VERIFY(v.at(1) == 1);
+  v.at(1) = 3;
+  VERIFY(v.at(1) == 3);
+  VERIFY(static_cast<const v1&>(v).at(1) == 3);
+
+#if __cpp_exceptions
+  try {
+    v.at(-1);
+    VERIFY(false);
+  } catch (const std::out_of_range&) {
+    VERIFY(true);
+  } catch (...) {
+    VERIFY(false);
+  }
+
+  try {
+    v.at(2);
+    VERIFY(false);
+  } catch (const std::out_of_range&) {
+    VERIFY(true);
+  } catch (...) {
+    VERIFY(false);
+  }
+#endif
+}
+
+int main() {
+  test01();
+
+#if __cpp_lib_view_interface != 202606L
+#error "Feature-test macro __cpp_lib_view_interface has wrong value in <ranges>"
+#endif
+}
-- 
2.54.0



More information about the Libstdc++ mailing list