// Copyright 2022 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef BASE_FUNCTIONAL_FUNCTION_REF_H_ #define BASE_FUNCTIONAL_FUNCTION_REF_H_ #include #include #include "base/functional/bind_internal.h" #include "third_party/abseil-cpp/absl/base/attributes.h" #include "third_party/abseil-cpp/absl/functional/function_ref.h" namespace base { template class FunctionRef; // A non-owning reference to any invocable object (e.g. function pointer, method // pointer, functor, lambda, et cetera) suitable for use as a type-erased // argument to ForEach-style functions or other visitor patterns that: // // - do not need to copy or take ownership of the argument // - synchronously call the invocable that was passed as an argument // // `base::FunctionRef` makes no heap allocations: it is trivially copyable and // should be passed by value. // // `base::FunctionRef` has no null/empty state: a `base::FunctionRef` is always // valid to invoke. // // The usual lifetime precautions for other non-owning references types (e.g. // `base::StringPiece`, `base::span`) also apply to `base::FunctionRef`. // `base::FunctionRef` should typically be used as an argument; returning a // `base::FunctionRef` or storing a `base::FunctionRef` as a field is dangerous // and likely to result in lifetime bugs. // // `base::RepeatingCallback` and `base::BindRepeating()` is another common way // to represent type-erased invocable objects. In contrast, it requires a heap // allocation and is not trivially copyable. It should be used when there are // ownership requirements (e.g. partial application of arguments to a function // stored for asynchronous execution). // // Note: `base::FunctionRef` is similar to `absl::FunctionRef`, but // with stricter conversions between function types. Return type conversions are // allowed (e.g. `int` -> `bool`, `Derived*` -> `Base*`); other than that, // function parameter types must match exactly, and return values may not be // silently discarded, e.g. `absl::FunctionRef` allows the following: // // // Silently discards `42`. // [] (absl::FunctionRef r) { // r(); // }([] { return 42; }); // // But with `base::FunctionRef`: // // // Does not compile! // [] (base::FunctionRef r) { // r(); // }([] { return 42; }); template class FunctionRef { private: template ::ReturnType, typename FunctorArgsAsTypeList = typename internal::BindTypeHelper::RunParamsList> using EnableIfCompatible = std::enable_if_t< std::is_convertible_v && std::is_same_v>>; public: // `ABSL_ATTRIBUTE_LIFETIME_BOUND` is important since `FunctionRef` retains // only a reference to `functor`, `functor` must outlive `this`. template > // NOLINTNEXTLINE(google-explicit-constructor) FunctionRef(const Functor& functor ABSL_ATTRIBUTE_LIFETIME_BOUND) : wrapped_func_ref_(functor) {} // Null FunctionRefs are not allowed. FunctionRef() = delete; FunctionRef(const FunctionRef&) = default; // Reduce the likelihood of lifetime bugs by disallowing assignment. FunctionRef& operator=(const FunctionRef&) = delete; R operator()(Args... args) const { return wrapped_func_ref_(std::forward(args)...); } absl::FunctionRef ToAbsl() const { return wrapped_func_ref_; } // In Chrome, converting to `absl::FunctionRef` should be explicitly done // through `ToAbsl()`. template operator absl::FunctionRef() = delete; private: absl::FunctionRef wrapped_func_ref_; }; } // namespace base #endif // BASE_FUNCTIONAL_FUNCTION_REF_H_