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 >> > > > >> > > >>
