[libcxx-commits] [libcxx] [libc++][RFC] Rewrite CPOs with resolver functions (PR #209104)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jul 30 06:35:03 PDT 2026


================
@@ -40,50 +42,50 @@ concept __can_borrow = is_lvalue_reference_v<_Tp> || enable_borrowed_range<remov
 
 namespace ranges {
 namespace __begin {
-template <class _Tp>
-concept __member_begin = __can_borrow<_Tp> && requires(_Tp&& __t) {
-  { _LIBCPP_AUTO_CAST(__t.begin()) } -> input_or_output_iterator;
-};
-
 void begin() = delete;
 
-template <class _Tp>
-concept __unqualified_begin =
-    !__member_begin<_Tp> && __can_borrow<_Tp> && __class_or_enum<remove_cvref_t<_Tp>> && requires(_Tp&& __t) {
-      { _LIBCPP_AUTO_CAST(begin(__t)) } -> input_or_output_iterator;
-    };
-
-struct __fn {
-  template <class _Tp>
-  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp (&__t)[]) const noexcept
-    requires(sizeof(_Tp) >= 0) // Disallow incomplete element types.
-  {
-    return __t + 0;
+struct __fn : _CPO<[]<class _Ep> consteval noexcept {
+  // [range.access.begin]
+
+  // Given a subexpression E with type T, let t be an lvalue that denotes the reified object for E. Then:
----------------
philnik777 wrote:

I don't think other implementations do this, though I haven't checked.

There are a few subtleties in how to write this, but it's mostly rather straight-forward AFAICT. Specifically, we have to make sure that the resolver function is marked `noexcept`, and that any lambdas we return are appropriately `noexcept`. Other than that, I don't think there are any pit-falls. Except for me missing some details in the wording that were caught by tests this code was incredibly straight-forward to write.

https://github.com/llvm/llvm-project/pull/209104


More information about the libcxx-commits mailing list