[libcxx-commits] [libcxx] WIP [libc++][ranges] P3052R2: `view_interface::at()` (PR #205012)
Hristo Hristov via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Jun 21 13:53:21 PDT 2026
https://github.com/H-G-Hristov created https://github.com/llvm/llvm-project/pull/205012
Closes #204395
Implements https://wg21.link/P3052R2
>From ad563100c32b586bf00c223a155ec233ad93278e Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 21 Jun 2026 23:52:40 +0300
Subject: [PATCH] [libc++][ranges] P3052R2: `view_interface::at()`
Closes #204395
Implements https://wg21.link/P3052R2
---
libcxx/include/__ranges/view_interface.h | 22 +++++++++++++++++++
.../view.interface/nodiscard.verify.cpp | 5 +++++
.../view.interface/view.interface.pass.cpp | 16 ++++++++++++++
3 files changed, 43 insertions(+)
diff --git a/libcxx/include/__ranges/view_interface.h b/libcxx/include/__ranges/view_interface.h
index 37b2c9e2c1a75..efe263e895d16 100644
--- a/libcxx/include/__ranges/view_interface.h
+++ b/libcxx/include/__ranges/view_interface.h
@@ -15,6 +15,7 @@
#include <__concepts/same_as.h>
#include <__config>
#include <__iterator/concepts.h>
+#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/prev.h>
#include <__memory/pointer_traits.h>
@@ -25,6 +26,7 @@
#include <__type_traits/is_class.h>
#include <__type_traits/make_unsigned.h>
#include <__type_traits/remove_cv.h>
+#include <stdexcept>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -159,6 +161,26 @@ class view_interface {
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](range_difference_t<_RARange> __index) const {
return ranges::begin(__derived())[__index];
}
+
+ template <random_access_range _RARange = _Derived>
+ requires sized_range<_RARange> // freestanding-deleted
+ [[nodiscard]] constexpr decltype(auto) at(range_difference_t<_RARange> __index) {
+ if (__index < 0 || __index >= ranges::distance(__derived())) {
+ std::__throw_out_of_range(
+ "Precondition `0 <= __index < distance()` not satisfied. `.at(__index)` called with out-of-bounds index.");
+ }
+ return (*this)[__index];
+ }
+
+ template <random_access_range _RARange = const _Derived>
+ requires sized_range<_RARange> // freestanding-deleted
+ [[nodiscard]] constexpr decltype(auto) at(range_difference_t<_RARange> __index) const {
+ if (__index < 0 || __index >= ranges::distance(__derived())) {
+ std::__throw_out_of_range(
+ "Precondition `0 <= __index < distance()` not satisfied. `.at(__index)` called with out-of-bounds index.");
+ }
+ return (*this)[__index];
+ }
};
} // namespace ranges
diff --git a/libcxx/test/libcxx/ranges/range.utility/view.interface/nodiscard.verify.cpp b/libcxx/test/libcxx/ranges/range.utility/view.interface/nodiscard.verify.cpp
index a22c03f5d1a71..5d076211bd5b3 100644
--- a/libcxx/test/libcxx/ranges/range.utility/view.interface/nodiscard.verify.cpp
+++ b/libcxx/test/libcxx/ranges/range.utility/view.interface/nodiscard.verify.cpp
@@ -67,4 +67,9 @@ void test() {
v[Diff{0}];
// expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
std::as_const(v)[Diff{0}];
+
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ v.at(Diff{0});
+ // expected-warning at +1 {{ignoring return value of function declared with 'nodiscard' attribute}}
+ std::as_const(v).at(Diff{0});
}
diff --git a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
index bce13c38f2dab..c170613e582ee 100644
--- a/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/view.interface/view.interface.pass.cpp
@@ -300,6 +300,22 @@ constexpr bool testSubscript() {
return true;
}
+template<class T>
+concept AtInvocable = requires (T const& obj, std::size_t n) { obj.at(n); };
+
+constexpr bool testAt() {
+ static_assert(!AtInvocable<ForwardRange>);
+ static_assert( AtInvocable<RARange>);
+
+ RARange randomAccess;
+ assert(randomAccess.at(2) == 2);
+ assert(static_cast<RARange const&>(randomAccess).at(2) == 2);
+ randomAccess.at(2) = 3;
+ assert(randomAccess.at(2) == 3);
+
+ return true;
+}
+
template<class T>
concept FrontInvocable = requires (T const& obj) { obj.front(); };
More information about the libcxx-commits
mailing list