On Fri, Sep 18, 2026 at 9:41 PM Tomasz Kaminski <[email protected]> wrote:
>
>
>
> On Fri, Sep 18, 2026 at 3:28 PM Yuao Ma <[email protected]> wrote:
>>
>> On Fri, Sep 18, 2026 at 9:15 PM Yuao Ma <[email protected]> wrote:
>> >
>> > On Fri, Sep 18, 2026 at 12:33 AM Jonathan Wakely <[email protected]> 
>> > wrote:
>> > >
>> > > >From 7c8c3330f775b98949705fa33ee0605989254b65 Mon Sep 17 00:00:00 2001
>> > > >From: Yuao Ma <[email protected]>
>> > > >Date: Thu, 17 Sep 2026 23:10:13 +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.
>> > > >       * include/std/ranges: Define __glibcxx_want_view_interface.
>> > > >       * testsuite/std/ranges/p3052.cc: New test.
>> > >
>> > > OK for trunk, thanks.
>> > >
>> > > >---
>> > > > libstdc++-v3/include/bits/ranges_util.h    | 23 +++++++++
>> > > > libstdc++-v3/include/bits/version.def      |  8 ++++
>> > > > libstdc++-v3/include/bits/version.h        | 10 ++++
>> > > > libstdc++-v3/include/std/ranges            |  1 +
>> > > > libstdc++-v3/testsuite/std/ranges/p3052.cc | 55 ++++++++++++++++++++++
>> > > > 5 files changed, 97 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..c14cdd7bd1e 100644
>> > > >--- a/libstdc++-v3/include/bits/ranges_util.h
>> > > >+++ b/libstdc++-v3/include/bits/ranges_util.h
>> > > >@@ -38,6 +38,9 @@
>> > > > #if __glibcxx_tuple_like // >= C++23
>> > > > # include <bits/stl_pair.h> // __pair_like, __is_tuple_like_v
>> > > > #endif
>> > > >+#if __glibcxx_view_interface // >= C++29
>> > > >+# include <bits/stdexcept_throw.h>
>> >
>> > Well this is a bit subtler than my original thought. This will cause a
>> > include cycle:  <tuple> -> ranges_util.h -> stdexcept_throw.h ->
>> > <string> -> memory_resource.h -> uses_allocator_args.h -> <tuple>.
>> >
>> > Includes # include <bits/stdexcept_throwfwd.h> can make the CI green,
>> > but not sure whether it is ideal.
>> >
>> > see also: https://patchwork.sourceware.org/patch/144067
>> >
>>
>> I did a little more digging, still can't find a more elegant way to
>> break the cycle...
>
> If you do not come up with anything else, you could define views_interface::at
> out of line in <ranges> header, and only forward declare in ranges_util.h

If the approach in https://forge.sourceware.org/gcc/gcc/pulls/235
isn't preferred, would it be acceptable to pursue this direction
instead?

>>
>>
>> > > >+#endif
>> > > >
>> > > > #ifdef __glibcxx_ranges
>> > > > namespace std _GLIBCXX_VISIBILITY(default)
>> > > >@@ -199,6 +202,26 @@ namespace ranges
>> > > >       operator[](range_difference_t<_Range> __n) const
>> > > >       { return ranges::begin(_M_derived())[__n]; }
>> > > >
>> > > >+#if __glibcxx_view_interface // >= C++29
>> > > >+      template<random_access_range _Range = _Derived>
>> > > >+      [[nodiscard]] 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>
>> > > >+      [[nodiscard]] 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/include/std/ranges 
>> > > >b/libstdc++-v3/include/std/ranges
>> > > >index a7fb2312fe8..f67ea82a0a2 100644
>> > > >--- a/libstdc++-v3/include/std/ranges
>> > > >+++ b/libstdc++-v3/include/std/ranges
>> > > >@@ -75,6 +75,7 @@
>> > > > #define __glibcxx_want_ranges_to_container
>> > > > #define __glibcxx_want_ranges_as_input
>> > > > #define __glibcxx_want_ranges_zip
>> > > >+#define __glibcxx_want_view_interface
>> > > > #include <bits/version.h>
>> > > >
>> > > > #ifdef __glibcxx_generator  // C++ >= 23 && __glibcxx_coroutine
>> > > >diff --git a/libstdc++-v3/testsuite/std/ranges/p3052.cc 
>> > > >b/libstdc++-v3/testsuite/std/ranges/p3052.cc
>> > > >new file mode 100644
>> > > >index 00000000000..d68d39df50c
>> > > >--- /dev/null
>> > > >+++ b/libstdc++-v3/testsuite/std/ranges/p3052.cc
>> > > >@@ -0,0 +1,55 @@
>> > > >+// { dg-do run { target c++29 } }
>> > > >+
>> > > >+#include <ranges>
>> > > >+
>> > > >+#if __cpp_lib_view_interface != 202606L
>> > > >+#error "Feature-test macro __cpp_lib_view_interface has wrong value in 
>> > > ><ranges>"
>> > > >+#endif
>> > > >+
>> > > >+#include <stdexcept>
>> > > >+
>> > > >+#include <testsuite_hooks.h>
>> > > >+
>> > > >+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 {
>> > > >+    static_cast<void>(v.at(-1));
>> > > >+    VERIFY(false);
>> > > >+  } catch (const std::out_of_range &) {
>> > > >+    VERIFY(true);
>> > > >+  } catch (...) {
>> > > >+    VERIFY(false);
>> > > >+  }
>> > > >+
>> > > >+  try {
>> > > >+    static_cast<void>(v.at(2));
>> > > >+    VERIFY(false);
>> > > >+  } catch (const std::out_of_range &) {
>> > > >+    VERIFY(true);
>> > > >+  } catch (...) {
>> > > >+    VERIFY(false);
>> > > >+  }
>> > > >+#endif
>> > > >+}
>> > > >+
>> > > >+int main() {
>> > > >+  test01();
>> > > >+  return 0;
>> > > >+}
>> > > >--
>> > > >2.54.0
>> > > >
>> > >
>>

Reply via email to