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. Mcro::Delegate::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
38namespace Mcro::Delegates
39{
40 using namespace Mcro::FunctionTraits;
41 using namespace Mcro::Tuples;
42
43 template <CFunctionLike Function, typename... Captures>
44 using TInferredDelegate = TDelegate<
47 TTrimEnd<sizeof...(Captures), typename TFunction<Function>::Arguments>
48 >,
49 FDefaultDelegateUserPolicy
50 >
51 ;
52
53 /** Maps to CreateStatic */
54 template <CFunctionLike Function, typename... Captures>
56 && (!CFunctorObject<Function>)
57 TInferredDelegate<Function, Captures...> From(Function func, const Captures&... captures)
58 {
60 }
61
62 /** Maps to CreateLambda */
63 template <CFunctorObject Function>
64 TDelegate<TFunction_Signature<Function>> From(Function&& func)
65 {
66 return TDelegate<TFunction_Signature<Function>>::CreateLambda(MoveTemp(func));
67 }
68
69 /** Maps to CreateSPLambda */
70 template <CSharedRef Object, CFunctorObject Function>
71 TDelegate<TFunction_Signature<Function>> From(const Object& self, Function&& func)
72 {
73 return TDelegate<TFunction_Signature<Function>>::CreateSPLambda(self, MoveTemp(func));
74 }
75
76 /** Maps to CreateSPLambda (SharedFromThis) */
77 template <CSharedFromThis Object, CFunctorObject Function>
78 TDelegate<TFunction_Signature<Function>> From(Object* self, Function&& func)
79 {
80 return TDelegate<TFunction_Signature<Function>>::CreateSPLambda(self, MoveTemp(func));
81 }
82
83 /** Maps to CreateSPLambda (SharedFromThis) */
84 template <CSharedFromThis Object, CFunctorObject Function>
85 TDelegate<TFunction_Signature<Function>> From(const Object* self, Function&& func)
86 {
87 return TDelegate<TFunction_Signature<Function>>::CreateSPLambda(self, MoveTemp(func));
88 }
89
90 /** Maps to CreateWeakLambda */
91 template <CPlainClass Object, CFunctorObject Function>
92 TDelegate<TFunction_Signature<Function>> From(Object* self, Function&& func)
93 {
94 return TDelegate<TFunction_Signature<Function>>::CreateWeakLambda(self, MoveTemp(func));
95 }
96
97 /** Maps to CreateRaw */
98 template <CPlainClass Object, CFunctionLike Function, typename... Captures>
99 requires TFunction_IsMember<Function> && (!CFunctorObject<Function>)
100 TInferredDelegate<Function, Captures...> From(Object* self, Function func, const Captures&... captures)
101 {
102 return TInferredDelegate<Function, Captures...>::CreateRaw(self, func, captures...);
103 }
104
105 /** Maps to CreateRaw */
106 template <CPlainClass Object, CFunctionLike Function, typename... Captures>
107 requires TFunction_IsMember<Function> && (!CFunctorObject<Function>)
108 TInferredDelegate<Function, Captures...> From(const Object* self, Function func, const Captures&... captures)
109 {
110 return TInferredDelegate<Function, Captures...>::CreateRaw(self, func, captures...);
111 }
112
113 /** Maps to CreateSP */
114 template <CSharedRef Object, CFunctionLike Function, typename... Captures>
115 requires TFunction_IsMember<Function> && (!CFunctorObject<Function>)
116 TInferredDelegate<Function, Captures...> From(const Object& self, Function func, const Captures&... captures)
117 {
118 return TInferredDelegate<Function, Captures...>::CreateSP(self, func, captures...);
119 }
120
121 /** Maps to CreateSP (SharedFromThis) */
122 template <CSharedFromThis Object, CFunctionLike Function, typename... Captures>
123 requires TFunction_IsMember<Function> && (!CFunctorObject<Function>)
124 TInferredDelegate<Function, Captures...> From(Object* self, Function func, const Captures&... captures)
125 {
126 return TInferredDelegate<Function, Captures...>::CreateSP(self, func, captures...);
127 }
128
129 /** Maps to CreateSP (SharedFromThis) */
130 template <CSharedFromThis Object, CFunctionLike Function, typename... Captures>
131 requires TFunction_IsMember<Function> && (!CFunctorObject<Function>)
132 TInferredDelegate<Function, Captures...> From(const Object* self, Function func, const Captures&... captures)
133 {
134 return TInferredDelegate<Function, Captures...>::CreateSP(self, func, captures...);
135 }
136
137 /** Maps to CreateUObject */
138 template <CUObject Object, CFunctionLike Function, typename... Captures>
140 && (!CFunctorObject<Function>)
141 TInferredDelegate<Function, Captures...> From(Object* self, Function func, const Captures&... captures)
142 {
143 return TInferredDelegate<Function, Captures...>::CreateUObject(self, func, captures...);
144 }
145
146 /** Maps to CreateUObject */
147 template <CUObject Object, CFunctionLike Function, typename... Captures>
149 && (!CFunctorObject<Function>)
150 TInferredDelegate<Function, Captures...> From(const Object* self, Function func, const Captures&... captures)
151 {
152 return TInferredDelegate<Function, Captures...>::CreateUObject(self, func, captures...);
153 }
154
155 /**
156 * Broadcast a multicast delegate when the returned delegate is executed.
157 * @param multicast input multicast delegate
158 *
159 * @todo Captures... and bound object
160 */
161 template <typename... Args>
162 TDelegate<void(Args...)> From(TMulticastDelegate<void(Args...)>& multicast)
163 {
164 return From([&](Args... args)
165 {
166 multicast.Broadcast(args...);
167 });
168 }
169
170 /**
171 * Broadcast a multicast delegate when the returned delegate is executed with a binding object.
172 * @param self any type of binding object other `From` overloads accept
173 * @param multicast input multicast delegate
174 *
175 * @todo Captures... and bound object
176 */
177 template <typename Object, typename... Args>
178 TDelegate<void(Args...)> From(Object&& self, TMulticastDelegate<void(Args...)>& multicast)
179 {
180 return From(Forward<Object>(self), [&](Args... args)
181 {
182 multicast.Broadcast(args...);
183 });
184 }
185
186 namespace Detail
187 {
188 template <CDynamicMulticastDelegate Dynamic, size_t... ArgIndices>
189 TNative<typename Dynamic::FDelegate> FromDynamicMulticastDelegate(Dynamic& multicast, std::index_sequence<ArgIndices...>&&)
190 {
191 return From([&](TFunction_Arg<TDynamicMethodPtr<Dynamic>, ArgIndices>... args)
192 {
193 multicast.Broadcast(args...);
194 });
195 }
196
197 template <typename Object, CDynamicMulticastDelegate Dynamic, size_t... ArgIndices>
198 TNative<typename Dynamic::FDelegate> FromDynamicMulticastDelegate(Object&& self, Dynamic& multicast, std::index_sequence<ArgIndices...>&&)
199 {
200 return From(Forward<Object>(self), [&](TFunction_Arg<TDynamicMethodPtr<Dynamic>, ArgIndices>... args)
201 {
202 multicast.Broadcast(args...);
203 });
204 }
205 }
206
207 /**
208 * Broadcast a dynamic multicast delegate when the returned delegate is executed.
209 * @tparam Dynamic The type of the input dynamic multicast delegate
210 * @param multicast input dynamic multicast delegate
211 *
212 * @todo Captures... and bound object
213 */
214 template <CDynamicMulticastDelegate Dynamic>
216 {
218 multicast,
219 std::make_index_sequence<
221 >{}
222 );
223 }
224
225
226 /**
227 * Broadcast a dynamic multicast delegate when the returned delegate is executed.
228 * @tparam Dynamic The type of the input dynamic multicast delegate
229 * @param self any type of binding object other `From` overloads accept
230 * @param multicast input dynamic multicast delegate
231 *
232 * @todo Captures... and bound object
233 */
234 template <typename Object, CDynamicMulticastDelegate Dynamic>
235 TNative<typename Dynamic::FDelegate> From(Object&& self, Dynamic& multicast)
236 {
238 Forward<Object>(self), multicast,
239 std::make_index_sequence<
241 >{}
242 );
243 }
244}
TNative< typename Dynamic::FDelegate > FromDynamicMulticastDelegate(Dynamic &multicast, std::index_sequence< ArgIndices... > &&)
typename TNative_Struct< std::decay_t< Dynamic > >::Type TNative
Definition Traits.h:97
TDelegate< TFunctionFromTuple< TFunction_Return< Function >, TTrimEnd< sizeof...(Captures), typename TFunction< Function >::Arguments > >, FDefaultDelegateUserPolicy > TInferredDelegate
TInferredDelegate< Function, Captures... > From(Function func, const Captures &... captures)
typename TDynamicMethodPtr_Struct< std::decay_t< Dynamic > >::Type TDynamicMethodPtr
Definition Traits.h:55
typename TFunctionTraits< std::decay_t< T > >::template Arg< I > TFunction_Arg
typename TFunctionTraits< std::decay_t< T > >::Return TFunction_Return
constexpr size_t TFunction_ArgCount
typename TFunctionFromTuple_Struct< std::decay_t< Return >, std::decay_t< Tuple > >::Type TFunctionFromTuple
constexpr bool TFunction_IsMember
typename TTrimEnd_Struct< Count, Tuple >::Type TTrimEnd
Definition Tuples.h:55