[libcxx-commits] [libcxx] [libc++] Implement `std::function_ref` (PR #186692)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jun 19 11:18:44 PDT 2026


================
@@ -0,0 +1,138 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// In case the function signature is taking an argument by value,
+// when the type is small and trivial, we pass it internally by value,
+// otherwise, we pass it by rvalue reference
+
+#include <cassert>
+#include <functional>
+#include <utility>
+#include <type_traits>
+
+struct Small {};
+
+struct Big {
+  char c[128];
+};
+
+struct SmallButNonTrivial {
+  Small s;
+  SmallButNonTrivial() = default;
+  SmallButNonTrivial(const SmallButNonTrivial&) {}
+};
+
+// Need to inspect the internal state of function_ref, and our implementation friend-ed all the function_ref
+// specializations, so we can just specialize an undefined function_ref here to inspect the defined ones
+template <>
+class std::function_ref<int> {
+  using storage = std::__function_ref_storage;
+  void test() {
+    {
+      // by value small argument
+      // the internal function should pass by value
+      using call = std::function_ref<void(Small)>::__call_t;
+      static_assert(std::is_same_v<call, void (*)(storage, Small)>);
+    }
+    {
+      // by value big argument
+      // the internal function should pass by rvalue reference
+      using call = std::function_ref<void(Big)>::__call_t;
+      static_assert(std::is_same_v<call, void (*)(storage, Big&&)>);
+    }
+    {
+      // by value non-trivial small argument
+      // the internal function should pass by rvalue reference to avoid unnecessary copy/move
+      using call = std::function_ref<void(SmallButNonTrivial)>::__call_t;
+      static_assert(std::is_same_v<call, void (*)(storage, SmallButNonTrivial&&)>);
+    }
+    {
+      // by lvalue reference argument
+      // the internal function should pass by lvalue reference
+      using call = std::function_ref<void(Small&)>::__call_t;
+      static_assert(std::is_same_v<call, void (*)(storage, Small&)>);
+    }
+    {
+      // by rvalue reference argument
+      // the internal function should pass by rvalue reference
+      using call = std::function_ref<void(Small&&)>::__call_t;
+      static_assert(std::is_same_v<call, void (*)(storage, Small&&)>);
+    }
+  }
+};
+
+struct TrackCopyMove {
+  mutable int copy_count = 0;
+  int move_count         = 0;
+
+  TrackCopyMove() = default;
+  TrackCopyMove(const TrackCopyMove& other) : copy_count(other.copy_count), move_count(other.move_count) {
+    ++copy_count;
+    ++other.copy_count;
+  }
+
+  TrackCopyMove(TrackCopyMove&& other) noexcept : copy_count(other.copy_count), move_count(other.move_count) {
+    ++move_count;
+    ++other.move_count;
+  }
+  TrackCopyMove& operator=(const TrackCopyMove& other) {
+    ++copy_count;
+    ++other.copy_count;
+    return *this;
+  }
+  TrackCopyMove& operator=(TrackCopyMove&& other) noexcept {
+    ++move_count;
+    ++other.move_count;
+    return *this;
+  }
+};
+
+void test() {
----------------
ldionne wrote:

I think there are two tests in this file. First, there's the quality-of-implementation codegen test above for trivial types.

Second, there's this test, which is actually (mostly) not specific to libc++. I'd move these observable tests to `libcxx/test/std`, with perhaps the third test-case for prvalues under `#if _LIBCPP_VERSION` if that one isn't standard-mandated.

For the first test about codegen, I'd use `FileCheck`, which we now support optionally in the libc++ test suite. That should allow you to do a normal codegen test like we do for LLVM.

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


More information about the libcxx-commits mailing list