4747#define ABSL_FUNCTIONAL_FUNCTION_REF_H_
4848
4949#include < cassert>
50- #include < functional>
5150#include < type_traits>
5251
5352#include " absl/base/attributes.h"
53+ #include " absl/base/config.h"
5454#include " absl/functional/internal/function_ref.h"
5555#include " absl/meta/type_traits.h"
56+ #include " absl/utility/utility.h"
5657
5758namespace absl {
5859ABSL_NAMESPACE_BEGIN
@@ -89,15 +90,17 @@ class FunctionRef<R(Args...)> {
8990 // signature of this FunctionRef.
9091 template <typename F, typename FR = std::invoke_result_t <F, Args&&...>>
9192 using EnableIfCompatible =
92- typename std::enable_if <std::is_void<R>::value ||
93- std::is_convertible<FR, R> ::value>::type ;
93+ std::enable_if_t <std::conditional_t <std::is_void_v<R>, std::true_type,
94+ std::is_invocable_r<R, FR()>> ::value>;
9495
9596 public:
9697 // Constructs a FunctionRef from any invocable type.
97- template <typename F, typename = EnableIfCompatible<const F&>>
98- // NOLINTNEXTLINE(runtime/explicit)
99- FunctionRef (const F& f ABSL_ATTRIBUTE_LIFETIME_BOUND)
100- : invoker_(&absl::functional_internal::InvokeObject<F, R, Args...>) {
98+ template <typename F,
99+ typename = EnableIfCompatible<std::enable_if_t <
100+ !std::is_same_v<FunctionRef, absl::remove_cvref_t <F>>, F&>>>
101+ // NOLINTNEXTLINE(google-explicit-constructor)
102+ FunctionRef (F&& f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
103+ : invoker_(&absl::functional_internal::InvokeObject<F&, R, Args...>) {
101104 absl::functional_internal::AssertNonNull (f);
102105 ptr_.obj = &f;
103106 }
@@ -111,14 +114,39 @@ class FunctionRef<R(Args...)> {
111114 template <
112115 typename F, typename = EnableIfCompatible<F*>,
113116 absl::functional_internal::EnableIf<absl::is_function<F>::value> = 0 >
114- FunctionRef (F* f) // NOLINT(runtime/explicit)
117+ // NOLINTNEXTLINE(google-explicit-constructor)
118+ FunctionRef (F* f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept
115119 : invoker_(&absl::functional_internal::InvokeFunction<F*, R, Args...>) {
116120 assert (f != nullptr );
117121 ptr_.fun = reinterpret_cast <decltype (ptr_.fun )>(f);
118122 }
119123
120- FunctionRef& operator =(const FunctionRef& rhs) = default ;
121- FunctionRef (const FunctionRef& rhs) = default ;
124+ #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
125+ // Similar to the other overloads, but passes the address of a known callable
126+ // `F` at compile time. This allows calling arbitrary functions while avoiding
127+ // an indirection.
128+ // Needs C++20 as `nontype_t` needs C++20 for `auto` template parameters.
129+ template <auto F>
130+ FunctionRef (nontype_t <F>) noexcept // NOLINT(google-explicit-constructor)
131+ : invoker_(&absl::functional_internal::InvokeFunction<decltype (F), F, R,
132+ Args...>) {}
133+
134+ template <auto F, typename Obj>
135+ // NOLINTNEXTLINE(google-explicit-constructor)
136+ FunctionRef (nontype_t <F>, Obj&& obj) noexcept
137+ : invoker_(&absl::functional_internal::InvokeObject<Obj&, decltype (F), F,
138+ R, Args...>) {
139+ ptr_.obj = std::addressof (obj);
140+ }
141+
142+ template <auto F, typename Obj>
143+ // NOLINTNEXTLINE(google-explicit-constructor)
144+ FunctionRef (nontype_t <F>, Obj* obj) noexcept
145+ : invoker_(&absl::functional_internal::InvokePtr<Obj, decltype (F), F, R,
146+ Args...>) {
147+ ptr_.obj = obj;
148+ }
149+ #endif
122150
123151 // Call the underlying object.
124152 R operator ()(Args... args) const {
@@ -134,8 +162,39 @@ class FunctionRef<R(Args...)> {
134162// constness anyway we can just make this a no-op.
135163template <typename R, typename ... Args>
136164class FunctionRef <R(Args...) const > : public FunctionRef<R(Args...)> {
165+ using Base = FunctionRef<R(Args...)>;
166+
167+ template <typename F, typename T = void >
168+ using EnableIfCallable =
169+ std::enable_if_t <!std::is_same_v<FunctionRef, absl::remove_cvref_t <F>> &&
170+ std::is_invocable_r_v<R, F, Args...> &&
171+ std::is_constructible_v<Base, F>,
172+ T>;
173+
137174 public:
138- using FunctionRef<R(Args...)>::FunctionRef;
175+ template <typename F, typename = EnableIfCallable<const F&>>
176+ // NOLINTNEXTLINE(google-explicit-constructor)
177+ FunctionRef (const F& f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept : Base(f) {}
178+
179+ template <typename F,
180+ typename = std::enable_if_t <std::is_constructible_v<Base, F*>>>
181+ // NOLINTNEXTLINE(google-explicit-constructor)
182+ FunctionRef (F* f ABSL_ATTRIBUTE_LIFETIME_BOUND) noexcept : Base(f) {}
183+
184+ #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L
185+ template <auto F, typename = EnableIfCallable<decltype (F)>>
186+ // NOLINTNEXTLINE(google-explicit-constructor)
187+ FunctionRef (nontype_t <F> arg) noexcept : Base(arg) {}
188+
189+ template <auto F, typename Obj, typename = EnableIfCallable<decltype (F)>>
190+ // NOLINTNEXTLINE(google-explicit-constructor)
191+ FunctionRef (nontype_t <F> arg, Obj&& obj) noexcept
192+ : Base(arg, std::forward<Obj>(obj)) {}
193+
194+ template <auto F, typename Obj, typename = EnableIfCallable<decltype (F)>>
195+ // NOLINTNEXTLINE(google-explicit-constructor)
196+ FunctionRef (nontype_t <F> arg, Obj* obj) noexcept : Base(arg, obj) {}
197+ #endif
139198};
140199
141200ABSL_NAMESPACE_END
0 commit comments