Drake
wrap_function.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <functional>
4 #include <type_traits>
5 #include <utility>
6 
7 namespace drake {
8 namespace pydrake {
9 namespace detail {
10 
11 // Collects both a functor object and its signature for ease of inference.
12 template <typename Func, typename Return, typename ... Args>
13 struct function_info {
14  // TODO(eric.cousineau): Ensure that this permits copy elision when combined
15  // with `std::forward<Func>(func)`, while still behaving well with primitive
16  // types.
17  std::decay_t<Func> func;
18 };
19 
20 // Factory method for `function_info<>`, to be used by `infer_function_info`.
21 template <typename Return, typename ... Args, typename Func>
22 auto make_function_info(Func&& func, Return (*infer)(Args...) = nullptr) {
23  (void)infer;
24  return function_info<Func, Return, Args...>{std::forward<Func>(func)};
25 }
26 
27 // SFINAE for functors.
28 // N.B. This *only* distinguished between function / method pointers and
29 // lambda objects. It does *not* distinguish among other types.
30 template <typename Func, typename T = void>
31 using enable_if_lambda_t =
32  std::enable_if_t<!std::is_function<std::decay_t<Func>>::value, T>;
33 
34 // Infers `function_info<>` from a function pointer.
35 template <typename Return, typename ... Args>
36 auto infer_function_info(Return (*func)(Args...)) {
37  return make_function_info<Return, Args...>(func);
38 }
39 
40 // Infers `function_info<>` from a mutable method pointer.
41 template <typename Return, typename Class, typename ... Args>
42 auto infer_function_info(Return (Class::*method)(Args...)) {
43  auto func = [method](Class* self, Args... args) {
44  return (self->*method)(std::forward<Args>(args)...);
45  };
46  return make_function_info<Return, Class*, Args...>(func);
47 }
48 
49 // Infers `function_info<>` from a const method pointer.
50 template <typename Return, typename Class, typename ... Args>
51 auto infer_function_info(Return (Class::*method)(Args...) const) {
52  auto func = [method](const Class* self, Args... args) {
53  return (self->*method)(std::forward<Args>(args)...);
54  };
55  return make_function_info<Return, const Class*, Args...>(func);
56 }
57 
58 // Helpers for general functor objects.
60  // Removes class from mutable method pointer for inferring signature
61  // of functor.
62  template <typename Class, typename Return, typename ... Args>
63  static auto remove_class_from_ptr(Return (Class::*)(Args...)) {
64  using Ptr = Return (*)(Args...);
65  return Ptr{};
66  }
67 
68  // Removes class from const method pointer for inferring signature of functor.
69  template <typename Class, typename Return, typename ... Args>
70  static auto remove_class_from_ptr(Return (Class::*)(Args...) const) {
71  using Ptr = Return (*)(Args...);
72  return Ptr{};
73  }
74 
75  // Infers funtion pointer from functor.
76  // @pre `Func` must have only *one* overload of `operator()`.
77  template <typename Func>
78  static auto infer_function_ptr() {
79  return remove_class_from_ptr(&Func::operator());
80  }
81 };
82 
83 // Infers `function_info<>` from a generic functor.
84 template <typename Func, typename = detail::enable_if_lambda_t<Func>>
85 auto infer_function_info(Func&& func) {
86  return make_function_info(
87  std::forward<Func>(func),
88  functor_helpers::infer_function_ptr<std::decay_t<Func>>());
89 }
90 
91 // Implementation for wrapping a function by scanning and replacing arguments
92 // based on their types.
93 template <
94  template <typename...> class wrap_arg_policy, bool use_functions = true>
96  // By default `wrap_arg_functions` is the same as `wrap_arg_policy`. However,
97  // below we specialize it for the case when `T` is of the form
98  // `std::function<F>`.
99  // N.B. This must precede `wrap_type`.
100  template <typename T>
101  struct wrap_arg_functions : public wrap_arg_policy<T> {};
102 
103  template <typename T>
104  using wrap_arg = std::conditional_t<
105  use_functions, wrap_arg_functions<T>, wrap_arg_policy<T>>;
106 
107  // Provides wrapped argument type.
108  // Uses `Extra` to specialize within class scope to intercept `void`.
109  template <typename T, typename Extra>
110  struct wrap_type {
111  using type = decltype(wrap_arg<T>::wrap(std::declval<T>()));
112  };
113 
114  // Intercept `void`, since `declval<void>()` is invalid.
115  template <typename Extra>
116  struct wrap_type<void, Extra> {
117  using type = void;
118  };
119 
120  // Convenience helper type.
121  template <typename T>
123 
124  // Determines which overload should be used, since we cannot wrap a `void`
125  // type using `wrap_arg<void>::wrap()`.
126  template <typename Return>
127  static constexpr bool enable_wrap_output =
129 
130  // Specialization for callbacks of the form `std::function<>`.
131  // @note We could generalize this using SFINAE for functors of any form, but
132  // that complicates the details for a relatively low ROI.
133  template <typename Return, typename ... Args>
134  struct wrap_arg_functions<const std::function<Return(Args...)>&> {
135  // Define types explicit, since `auto` is not easily usable as a return type
136  // (compilers struggle with inference).
137  using Func = std::function<Return(Args...)>;
138  using WrappedFunc =
139  std::function<wrap_type_t<Return> (wrap_type_t<Args>...)>;
140 
141  static WrappedFunc wrap(const Func& func) {
143  }
144 
145  // Unwraps a `WrappedFunc`, also unwrapping the return value.
146  // @note We use `Defer` so that we can use SFINAE without a disptach method.
147  template <typename Defer = Return>
148  static Func unwrap(
149  const WrappedFunc& func_wrapped,
150  std::enable_if_t<enable_wrap_output<Defer>, void*> = {}) {
151  return [func_wrapped](Args... args) -> Return {
153  func_wrapped(wrap_arg_functions<Args>::wrap(
154  std::forward<Args>(args))...));
155  };
156  }
157 
158  // Specialization / overload of above, but not wrapping the return value.
159  template <typename Defer = Return>
160  static Func unwrap(
161  const WrappedFunc& func_wrapped,
162  std::enable_if_t<!enable_wrap_output<Defer>, void*> = {}) {
163  return [func_wrapped](Args... args) {
164  func_wrapped(wrap_arg_functions<Args>::wrap(
165  std::forward<Args>(args))...);
166  };
167  }
168  };
169 
170  // Ensure that we also wrap `std::function<>` returned by value.
171  template <typename Signature>
172  struct wrap_arg_functions<std::function<Signature>>
173  : public wrap_arg_functions<const std::function<Signature>&> {};
174 
175  // Wraps function arguments and the return value.
176  // Generally used when `Return` is non-void.
177  template <typename Func, typename Return, typename ... Args>
179  std::enable_if_t<enable_wrap_output<Return>, void*> = {}) {
180  // N.B. Since we do not use the `mutable` keyword with this lambda,
181  // any functors passed in *must* provide `operator()(...) const`.
182  auto func_wrapped =
183  [func_f = std::forward<Func>(info.func)]
184  (wrap_type_t<Args>... args_wrapped) -> wrap_type_t<Return> {
185  return wrap_arg<Return>::wrap(
186  func_f(wrap_arg<Args>::unwrap(
187  std::forward<wrap_type_t<Args>>(args_wrapped))...));
188  };
189  return func_wrapped;
190  }
191 
192  // Wraps function arguments, but not the return value.
193  // Generally used when `Return` is void.
194  template <typename Func, typename Return, typename ... Args>
196  std::enable_if_t<!enable_wrap_output<Return>, void*> = {}) {
197  auto func_wrapped =
198  [func_f = std::forward<Func>(info.func)]
199  (wrap_type_t<Args>... args_wrapped) -> Return {
200  return func_f(wrap_arg<Args>::unwrap(
201  std::forward<wrap_type_t<Args>>(args_wrapped))...);
202  };
203  return func_wrapped;
204  }
205 };
206 
207 } // namespace detail
208 
209 /// Wraps the types used in a function signature to produce a new function with
210 /// wrapped arguments and return value (if non-void). The wrapping is based on
211 /// `wrap_arg_policy`.
212 /// Any types that are of the form `std::function<F>` will be recursively
213 /// wrapped, such that callbacks will be of a wrapped form (arguments and
214 /// return types wrapped). The original form of the callbacks will still be
215 /// called in the wrapped callback.
216 /// @tparam wrap_arg_policy
217 /// User-supplied argument wrapper, that must supply the static functions
218 /// `wrap(Arg arg) -> Wrapped` and `unwrap(Wrapped wrapped) -> Arg`.
219 /// `Arg arg` is the original argument, and `Wrapped wrapped` is the wrapped
220 /// / transformed argument type.
221 /// N.B. This template template parameter uses a parameter pack to allow
222 /// for SFINAE. If passing a `using` template alias, ensure that the alias
223 /// template template parameter uses a parameter pack of the *exact* same
224 /// form.
225 /// @tparam use_functions
226 /// If true (default), will recursively wrap callbacks. If your policy
227 /// provides handling for functions, then you should set this to false.
228 /// @param func
229 /// Functor to be wrapped. Returns a function with wrapped arugments and
230 /// return type. If functor is a method pointer, it will return a function of
231 /// the form `Return ([const] Class* self, ...)`.
232 /// @return Wrapped function lambda.
233 /// N.B. Construct a `std::function<>` from this if you encounter inference
234 /// issues downstream of this method.
235 template <
236  template <typename...> class wrap_arg_policy, bool use_functions = true,
237  typename Func = void>
238 auto WrapFunction(Func&& func) {
239  // TODO(eric.cousineau): Create an overload with `type_pack<Args...>` to
240  // handle overloads, to disambiguate when necessary.
242  detail::infer_function_info(std::forward<Func>(func)));
243 }
244 
245 /// Default case for argument wrapping, with pure pass-through. Consider
246 /// inheriting from this for base cases.
247 /// N.B. `Wrapped` is not necessary, but is used for demonstration purposes.
248 template <typename T>
250  using Wrapped = T;
251  static Wrapped wrap(T arg) { return std::forward<T&&>(arg); }
252  static T unwrap(Wrapped arg_wrapped) {
253  return std::forward<Wrapped&&>(arg_wrapped);
254  }
255  // N.B. `T` rather than `T&&` is used as arguments here as it behaves well
256  // with primitve types, such as `int`.
257 };
258 
259 /// Policy for explicitly wrapping functions for a given policy.
260 template <template <typename...> class wrap_arg_policy, typename Signature>
261 using wrap_arg_function =
263  template wrap_arg<std::function<Signature>>;
264 
265 } // namespace pydrake
266 } // namespace drake
typename detail::wrap_function_impl< wrap_arg_policy >::template wrap_arg< std::function< Signature >> wrap_arg_function
Policy for explicitly wrapping functions for a given policy.
Definition: wrap_function.h:263
const T * Wrapped
Definition: wrap_function.h:250
std::enable_if_t<!std::is_function< std::decay_t< Func >>::value, T > enable_if_lambda_t
Definition: wrap_function.h:32
double value
Definition: wrap_test_util_py.cc:12
Definition: automotive_demo.cc:90
static auto remove_class_from_ptr(Return(Class::*)(Args...))
Definition: wrap_function.h:63
STL namespace.
std::function< wrap_type_t< Return >(wrap_type_t< Args >...)> WrappedFunc
Definition: wrap_function.h:139
static T unwrap(Wrapped arg_wrapped)
Definition: wrap_function.h:252
Definition: wrap_function.h:13
static Wrapped wrap(T arg)
Definition: wrap_function.h:251
static auto remove_class_from_ptr(Return(Class::*)(Args...) const)
Definition: wrap_function.h:70
typename wrap_type< T, void >::type wrap_type_t
Definition: wrap_function.h:122
std::decay_t< Func > func
Definition: wrap_function.h:17
Definition: wrap_function.h:95
std::conditional_t< use_functions, wrap_arg_functions< T >, wrap_arg_policy< T >> wrap_arg
Definition: wrap_function.h:105
auto infer_function_info(Return(*func)(Args...))
Definition: wrap_function.h:36
auto WrapFunction(Func &&func)
Wraps the types used in a function signature to produce a new function with wrapped arguments and ret...
Definition: wrap_function.h:238
decltype(wrap_arg< T >::wrap(std::declval< T >())) type
Definition: wrap_function.h:111
static Func unwrap(const WrappedFunc &func_wrapped, std::enable_if_t<!enable_wrap_output< Defer >, void * >={})
Definition: wrap_function.h:160
static auto run(function_info< Func, Return, Args... > &&info, std::enable_if_t<!enable_wrap_output< Return >, void * >={})
Definition: wrap_function.h:195
Definition: wrap_function.h:59
auto make_function_info(Func &&func, Return(*infer)(Args...)=nullptr)
Definition: wrap_function.h:22
static auto run(function_info< Func, Return, Args... > &&info, std::enable_if_t< enable_wrap_output< Return >, void * >={})
Definition: wrap_function.h:178
Default case for argument wrapping, with pure pass-through.
Definition: wrap_function.h:249
static auto infer_function_ptr()
Definition: wrap_function.h:78
static Func unwrap(const WrappedFunc &func_wrapped, std::enable_if_t< enable_wrap_output< Defer >, void * >={})
Definition: wrap_function.h:148