MCRO
C++23 utilities for Unreal Engine.
Loading...
Searching...
No Matches
DelegateFrom.h
Go to the documentation of this file.
1/** @noop License Comment
2 * @file
3 * @copyright
4 * This Source Code is subject to the terms of the Mozilla Public License, v2.0.
5 * If a copy of the MPL was not distributed with this file You can obtain one at
6 * https://mozilla.org/MPL/2.0/
7 *
8 * @author David Mórász
9 * @date 2025
10 */
11
12#pragma once
13
14/**
15 * @file
16 * Unreal delegates while being great they have the problem that they're pretty verbose to use, as the usage site
17 * requires the developer to spell out the delegate types when they're being bound to something. `InferDelegate::From`
18 * overloads not only infer delegate types from input function, but they also infer how the delegate is being used.
19 * For example take `From(this, &FStuff::MyFunc)` can map to several classic delegate usages depending on the type of
20 * `this`:
21 * - CreateSP if `this` is TSharedFromThis
22 * - CreateUObject if `this` is a UObject
23 * - CreateRaw in case `this` is just a plain old C++ object
24 * @file
25 * `From` can also deal with
26 * - usages of Lambda functions with same API
27 * - correct delegate type from combination of given function signature and given captures
28 * - So `From(this, &FStuff::MyFunc, TEXT_"my capture")` will correctly remove the last argument from the function
29 * signature of `FStuff::MyFunc` when inferring the delegate type.
30 * - Chain multicast delegates together
31 */
32
33#include "CoreMinimal.h"
34#include "Mcro/FunctionTraits.h"
36#include "Mcro/Tuples.h"
37
38/**
39 * @brief The extra layer of namespace `InferDelegate` is there for guarding common vocabulary (From) but still
40 * allowing the developer to use this namespace for a more terse syntax.
41 */
43{
44 using namespace Mcro::FunctionTraits;
45 using namespace Mcro::Tuples;
46
47 /**
48 * @brief
49 * Instead of specifying manually a delegate type, infer it from the input function and the extra captures.
50 *
51 * This overload is equivalent to `TDelegate::CreateStatic`
52 */
53 template <CFunctionPtr Function, typename... Captures>
54 requires (!CFunction_IsMember<Function>)
55 && (!CFunctorObject<Function>)
56 TInferredDelegate<Function, Captures...> From(Function func, Captures&&... captures)
57 {
59 }
60
61 /**
62 * @brief
63 * Instead of specifying manually a delegate type, infer it from the input function and the extra captures.
64 *
65 * This overload is equivalent to `TDelegate::CreateLambda`
66 */
67 template <CFunctorObject Function>
68 TDelegate<TFunction_Signature<Function>> From(Function&& func)
69 {
70 return TDelegate<TFunction_Signature<Function>>::CreateLambda(FWD(func));
71 }
72
73 /**
74 * @brief
75 * Instead of specifying manually a delegate type, infer it from the input function and the extra captures. Also
76 * infer the method of object binding based on the type traits of the object argument.
77 *
78 * This overload is equivalent to `TDelegate::CreateSPLambda` (TSharedRef)
79 */
80 template <CSharedRef Object, CFunctorObject Function>
81 TDelegate<TFunction_Signature<Function>> From(Object const& self, Function&& func)
82 {
83 return TDelegate<TFunction_Signature<Function>>::CreateSPLambda(self, FWD(func));
84 }
85
86 /**
87 * @brief
88 * Instead of specifying manually a delegate type, infer it from the input function and the extra captures. Also
89 * infer the method of object binding based on the type traits of the object argument.
90 *
91 * This overload is equivalent to `TDelegate::CreateSPLambda` (TSharedFromThis pointer)
92 */
93 template <CSharedFromThis Object, CFunctorObject Function>
94 TDelegate<TFunction_Signature<Function>> From(Object* self, Function&& func)
95 {
96 return TDelegate<TFunction_Signature<Function>>::CreateSPLambda(self, FWD(func));
97 }
98
99 /**
100 * @brief
101 * Instead of specifying manually a delegate type, infer it from the input function and the extra captures. Also
102 * infer the method of object binding based on the type traits of the object argument.
103 *
104 * This overload is equivalent to `TDelegate::CreateSPLambda` (TSharedFromThis const pointer)
105 */
106 template <CSharedFromThis Object, CFunctorObject Function>
107 TDelegate<TFunction_Signature<Function>> From(const Object* self, Function&& func)
108 {
109 return TDelegate<TFunction_Signature<Function>>::CreateSPLambda(self, FWD(func));
110 }
111
112 /**
113 * @brief
114 * Instead of specifying manually a delegate type, infer it from the input function and the extra captures. Also
115 * infer the method of object binding based on the type traits of the object argument.
116 *
117 * This overload is equivalent to `TDelegate::CreateRaw` (plain C++ object pointer)
118 */
119 template <CPlainClass Object, CFunctionPtr Function, typename... Captures>
120 requires CFunction_IsMember<Function>
121 TInferredDelegate<Function, Captures...> From(Object* self, Function func, const Captures&... captures)
122 {
123 return TInferredDelegate<Function, Captures...>::CreateRaw(self, func, captures...);
124 }
125
126 /**
127 * @brief
128 * Instead of specifying manually a delegate type, infer it from the input function and the extra captures. Also
129 * infer the method of object binding based on the type traits of the object argument.
130 *
131 * This overload is equivalent to `TDelegate::CreateRaw` (plain C++ const object pointer)
132 */
133 template <CPlainClass Object, CFunctionPtr Function, typename... Captures>
134 requires CFunction_IsMember<Function>
135 TInferredDelegate<Function, Captures...> From(const Object* self, Function func, const Captures&... captures)
136 {
137 return TInferredDelegate<Function, Captures...>::CreateRaw(self, func, captures...);
138 }
139
140 /**
141 * @brief
142 * Instead of specifying manually a delegate type, infer it from the input function and the extra captures. Also
143 * infer the method of object binding based on the type traits of the object argument.
144 *
145 * This overload is equivalent to `TDelegate::CreateSP` (TSharedRef)
146 */
147 template <CSharedRef Object, CFunctionPtr Function, typename... Captures>
148 requires CFunction_IsMember<Function>
149 TInferredDelegate<Function, Captures...> From(const Object& self, Function func, const Captures&... captures)
150 {
151 return TInferredDelegate<Function, Captures...>::CreateSP(self, func, captures...);
152 }
153
154 /**
155 * @brief
156 * Instead of specifying manually a delegate type, infer it from the input function and the extra captures. Also
157 * infer the method of object binding based on the type traits of the object argument.
158 *
159 * This overload is equivalent to `TDelegate::CreateSP` (TSharedFromThis pointer)
160 */
161 template <CSharedFromThis Object, CFunctionPtr Function, typename... Captures>
162 requires CFunction_IsMember<Function>
163 TInferredDelegate<Function, Captures...> From(Object* self, Function func, const Captures&... captures)
164 {
165 return TInferredDelegate<Function, Captures...>::CreateSP(self, func, captures...);
166 }
167
168 /**
169 * @brief
170 * Instead of specifying manually a delegate type, infer it from the input function and the extra captures. Also
171 * infer the method of object binding based on the type traits of the object argument.
172 *
173 * This overload is equivalent to `TDelegate::CreateSP` (TSharedFromThis const pointer)
174 */
175 template <CSharedFromThis Object, CFunctionPtr Function, typename... Captures>
176 requires CFunction_IsMember<Function>
177 TInferredDelegate<Function, Captures...> From(const Object* self, Function func, const Captures&... captures)
178 {
179 return TInferredDelegate<Function, Captures...>::CreateSP(self, func, captures...);
180 }
181
182 /**
183 * @brief
184 * Instead of specifying manually a delegate type, infer it from the input function and the extra captures. Also
185 * infer the method of object binding based on the type traits of the object argument.
186 *
187 * This overload is equivalent to `TDelegate::CreateWeakLambda` (UObject)
188 */
189 template <CUObject Object, CFunctorObject Function>
190 TDelegate<TFunction_Signature<Function>> From(Object* self, Function&& func)
191 {
192 return TDelegate<TFunction_Signature<Function>>::CreateWeakLambda(self, FWD(func));
193 }
194
195 /**
196 * @brief
197 * Instead of specifying manually a delegate type, infer it from the input function and the extra captures. Also
198 * infer the method of object binding based on the type traits of the object argument.
199 *
200 * This overload is equivalent to `TDelegate::CreateUObject` (UObject pointer)
201 */
202 template <CUObject Object, CFunctionPtr Function, typename... Captures>
203 requires CFunction_IsMember<Function>
204 TInferredDelegate<Function, Captures...> From(Object* self, Function func, const Captures&... captures)
205 {
206 return TInferredDelegate<Function, Captures...>::CreateUObject(self, func, captures...);
207 }
208
209 /**
210 * @brief
211 * Instead of specifying manually a delegate type, infer it from the input function and the extra captures. Also
212 * infer the method of object binding based on the type traits of the object argument.
213 *
214 * This overload is equivalent to `TDelegate::CreateUObject` (UObject const pointer)
215 */
216 template <CUObject Object, CFunctionPtr Function, typename... Captures>
217 requires CFunction_IsMember<Function>
218 TInferredDelegate<Function, Captures...> From(const Object* self, Function func, const Captures&... captures)
219 {
220 return TInferredDelegate<Function, Captures...>::CreateUObject(self, func, captures...);
221 }
222
223 /**
224 * @brief
225 * Instead of specifying manually a delegate type, infer it from the input function and the extra captures. Also
226 * infer the method of object binding based on the type traits of the object argument.
227 *
228 * This overload is equivalent to `TDelegate::CreateUObject` (TObjectPtr)
229 */
230 template <CUObject Object, CFunctionPtr Function, typename... Captures>
231 requires CFunction_IsMember<Function>
232 TInferredDelegate<Function, Captures...> From(TObjectPtr<Object> self, Function func, const Captures&... captures)
233 {
234 return TInferredDelegate<Function, Captures...>::CreateUObject(self, func, captures...);
235 }
236
237 /**
238 * @brief Broadcast a multicast delegate when the returned delegate is executed.
239 * @param multicast input multicast delegate
240 *
241 * @todo Captures... and bound object
242 */
243 template <typename... Args>
244 TDelegate<void(Args...)> From(TMulticastDelegate<void(Args...)>& multicast)
245 {
246 return From([&](Args... args)
247 {
248 multicast.Broadcast(args...);
249 });
250 }
251
252 /**
253 * @brief Broadcast a multicast delegate when the returned delegate is executed with a binding object.
254 * @param self any type of binding object other `From` overloads accept
255 * @param multicast input multicast delegate
256 *
257 * @todo Captures... and bound object
258 */
259 template <typename Object, typename... Args>
260 TDelegate<void(Args...)> From(Object&& self, TMulticastDelegate<void(Args...)>& multicast)
261 {
262 return From(FWD(self), [&](Args... args)
263 {
264 multicast.Broadcast(args...);
265 });
266 }
267
268 namespace Detail
269 {
270 template <CDynamicMulticastDelegate Dynamic, size_t... ArgIndices>
271 TNative<typename Dynamic::FDelegate> FromDynamicMulticastDelegate(Dynamic& multicast, std::index_sequence<ArgIndices...>&&)
272 {
273 return From([&](TFunction_Arg<TDynamicMethodPtr<Dynamic>, ArgIndices>... args)
274 {
275 multicast.Broadcast(args...);
276 });
277 }
278
279 template <typename Object, CDynamicMulticastDelegate Dynamic, size_t... ArgIndices>
280 TNative<typename Dynamic::FDelegate> FromDynamicMulticastDelegate(Object&& self, Dynamic& multicast, std::index_sequence<ArgIndices...>&&)
281 {
282 return From(FWD(self), [&](TFunction_Arg<TDynamicMethodPtr<Dynamic>, ArgIndices>... args)
283 {
284 multicast.Broadcast(args...);
285 });
286 }
287 }
288
289 /**
290 * @brief Broadcast a dynamic multicast delegate when the returned delegate is executed.
291 * @tparam Dynamic The type of the input dynamic multicast delegate
292 * @param multicast input dynamic multicast delegate
293 *
294 * @todo Captures... and bound object
295 */
296 template <CDynamicMulticastDelegate Dynamic>
298 {
300 multicast,
301 std::make_index_sequence<
303 >{}
304 );
305 }
306
307
308 /**
309 * @brief Broadcast a dynamic multicast delegate when the returned delegate is executed.
310 * @tparam Dynamic The type of the input dynamic multicast delegate
311 * @param self any type of binding object other `From` overloads accept
312 * @param multicast input dynamic multicast delegate
313 *
314 * @todo Captures... and bound object
315 */
316 template <typename Object, CDynamicMulticastDelegate Dynamic>
317 TNative<typename Dynamic::FDelegate> From(Object&& self, Dynamic& multicast)
318 {
320 FWD(self), multicast,
321 std::make_index_sequence<
323 >{}
324 );
325 }
326}
#define FWD(...)
Shorten forwarding expression with this macro so one may not need to specify explicit type.
Definition Macros.h:100
Constraint given type to a dynamic multicast delegate class.
Definition Traits.h:51
TNative< typename Dynamic::FDelegate > FromDynamicMulticastDelegate(Dynamic &multicast, std::index_sequence< ArgIndices... > &&)
The extra layer of namespace InferDelegate is there for guarding common vocabulary (From) but still a...
TInferredDelegate< Function, Captures... > From(Function func, Captures &&... captures)
Instead of specifying manually a delegate type, infer it from the input function and the extra captur...
typename TNative_Struct< std::decay_t< Dynamic > >::Type TNative
Map the input dynamic (multicast) delegate to a conceptually compatible native (multicast) delegate t...
Definition Traits.h:111
TDelegate< TFunctionFromTuple< TFunction_Return< Function >, TTrimEnd< sizeof...(Captures), TFunction_Arguments< Function > > >, FDefaultDelegateUserPolicy > TInferredDelegate
Infer a delegate type from an input function signature and a list of captures.
Definition Traits.h:33
typename TDynamicMethodPtr_Struct< std::decay_t< Dynamic > >::Type TDynamicMethodPtr
Get the native function pointer type compatible with given dynamic (multicast) delegate.
Definition Traits.h:73
typename TFunctionTraits< std::decay_t< T > >::template Arg< I > TFunction_Arg
Shorthand for getting a type of a function argument at given position I.
constexpr size_t TFunction_ArgCount
Shorthand for getting a function argument count.
Templating utilities for manipulating TTuples.
Definition Tuples.h:24