Embedded Template Library 1.0
Loading...
Searching...
No Matches
invoke.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2025 John Wellbelove
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31#ifndef ETL_INVOKE_INCLUDED
32#define ETL_INVOKE_INCLUDED
33
34#include "platform.h"
35#include "function_traits.h"
36#include "functional.h"
37#include "type_traits.h"
38#include "utility.h"
39
40#if ETL_USING_CPP11
41
42namespace etl
43{
44 //****************************************************************************
45 // invoke implementation
46 //****************************************************************************
47
48 //****************************************************************************
50 template < typename TFunction, typename TRefWrapper, typename... TArgs,
51 typename = etl::enable_if_t< etl::is_member_function_pointer<etl::decay_t<TFunction>>::value
52 && etl::is_reference_wrapper<etl::decay_t<TRefWrapper>>::value>>
53 ETL_CONSTEXPR auto invoke(TFunction&& f, TRefWrapper&& ref_wrapper, TArgs&&... args) -> decltype((ref_wrapper.get().*f)(etl::forward<TArgs>(args)...))
54 {
55 return (ref_wrapper.get().*f)(etl::forward<TArgs>(args)...);
56 }
57
58 //****************************************************************************
60 template <
61 typename TFunction, typename TPtr, typename... TArgs,
62 typename = etl::enable_if_t< etl::is_member_function_pointer<etl::decay_t<TFunction>>::value && etl::is_pointer<etl::decay_t<TPtr>>::value>>
63 ETL_CONSTEXPR auto invoke(TFunction&& f, TPtr&& ptr, TArgs&&... args) -> decltype(((*etl::forward<TPtr>(ptr)).*f)(etl::forward<TArgs>(args)...))
64 {
65 return ((*etl::forward<TPtr>(ptr)).*f)(etl::forward<TArgs>(args)...);
66 }
67
68 //****************************************************************************
70 template < typename TFunction, typename TObject, typename... TArgs,
71 typename = etl::enable_if_t< etl::is_member_function_pointer<etl::decay_t<TFunction>>::value
72 && !etl::is_pointer<etl::decay_t<TObject>>::value && !is_reference_wrapper<etl::decay_t<TObject>>::value>>
73 ETL_CONSTEXPR auto invoke(TFunction&& f, TObject&& obj, TArgs&&... args) -> decltype((etl::forward<TObject>(obj).*f)(etl::forward<TArgs>(args)...))
74 {
75 return (etl::forward<TObject>(obj).*f)(etl::forward<TArgs>(args)...);
76 }
77
78 //****************************************************************************
80 template < typename TFunction, typename TRefWrapper,
81 typename = etl::enable_if_t< etl::is_member_object_pointer<etl::decay_t<TFunction>>::value
82 && etl::is_reference_wrapper<etl::decay_t<TRefWrapper>>::value>>
83 ETL_CONSTEXPR auto invoke(TFunction&& f, TRefWrapper&& ref_wrapper) -> decltype(ref_wrapper.get().*f)
84 {
85 return ref_wrapper.get().*f;
86 }
87
88 //****************************************************************************
90 template <
91 typename TFunction, typename TPtr,
92 typename = etl::enable_if_t< etl::is_member_object_pointer<etl::decay_t<TFunction>>::value && etl::is_pointer<etl::decay_t<TPtr>>::value>>
93 ETL_CONSTEXPR auto invoke(TFunction&& f, TPtr&& ptr) -> decltype(((*etl::forward<TPtr>(ptr)).*f))
94 {
95 return ((*etl::forward<TPtr>(ptr)).*f);
96 }
97
98 //****************************************************************************
100 template < typename TFunction, typename TObject,
101 typename = etl::enable_if_t< etl::is_member_object_pointer<etl::decay_t<TFunction>>::value
102 && !etl::is_pointer<etl::decay_t<TObject>>::value && !is_reference_wrapper<etl::decay_t<TObject>>::value>>
103 ETL_CONSTEXPR auto invoke(TFunction&& f, TObject&& obj) -> decltype(etl::forward<TObject>(obj).*f)
104 {
105 return etl::forward<TObject>(obj).*f;
106 }
107
108 //****************************************************************************
110 template < typename TFunction, typename... TArgs,
111 typename = etl::enable_if_t< etl::is_reference_wrapper<etl::decay_t<TFunction>>::value
112 && !etl::is_member_pointer<etl::decay_t< decltype(etl::declval<TFunction>().get())>>::value>>
113 ETL_CONSTEXPR auto invoke(TFunction&& f, TArgs&&... args) -> decltype(f.get()(etl::forward<TArgs>(args)...))
114 {
115 return f.get()(etl::forward<TArgs>(args)...);
116 }
117
118 //****************************************************************************
121 template < typename TFunction, typename... TArgs,
122 typename = etl::enable_if_t< etl::is_reference_wrapper<etl::decay_t<TFunction>>::value
123 && etl::is_member_pointer<etl::decay_t< decltype(etl::declval<TFunction>().get())>>::value>,
124 typename = void>
125 ETL_CONSTEXPR auto invoke(TFunction&& f, TArgs&&... args) -> decltype(etl::invoke(f.get(), etl::forward<TArgs>(args)...))
126 {
127 return etl::invoke(f.get(), etl::forward<TArgs>(args)...);
128 }
129
130 //****************************************************************************
132 template < typename TFunction, typename... TArgs,
133 typename = etl::enable_if_t< !etl::is_member_pointer<etl::decay_t<TFunction>>::value
134 && !etl::is_reference_wrapper<etl::decay_t<TFunction>>::value>>
135 ETL_CONSTEXPR auto invoke(TFunction&& f, TArgs&&... args) -> decltype(etl::forward<TFunction>(f)(etl::forward<TArgs>(args)...))
136 {
137 return etl::forward<TFunction>(f)(etl::forward<TArgs>(args)...);
138 }
139
140 //****************************************************************************
141 // is_invocable implementation
142 //****************************************************************************
143 namespace private_invoke
144 {
145 //*******************************************
146 // Core detection of invocability.
147 // Succeeds if the invocation expression is well-formed.
148 template <typename TFunction, typename... TArgs>
149 struct is_invocable_expr
150 {
151 template <typename U>
152 static auto test(int) -> decltype((void)etl::invoke(etl::declval<U>(), etl::declval<TArgs>()...), etl::true_type{});
153
154 template <typename>
155 static etl::false_type test(...);
156
157 using type = decltype(test<TFunction>(0));
158
159 static ETL_CONSTANT bool value = type::value;
160 };
161
162 //*******************************************
163 // Core detection of invocability.
164 // Succeeds if the invocation expression is well-formed.
165 // Using etl::type_list for the argument list.
166 template <typename TFunction, typename... TArgs>
167 struct is_invocable_expr<TFunction, etl::type_list<TArgs...>>
168 {
169 template <typename U>
170 static auto test(int) -> decltype((void)etl::invoke(etl::declval<U>(), etl::declval<TArgs>()...), etl::true_type{});
171
172 template <typename>
173 static etl::false_type test(...);
174
175 using type = decltype(test<TFunction>(0));
176
177 static ETL_CONSTANT bool value = type::value;
178 };
179
180 //*******************************************
181 // Result type of a valid invocation.
182 template <typename TFunction, typename... TArgs>
183 struct invoke_result_impl
184 {
185 template <typename U>
186 static auto test(int) -> decltype(etl::invoke(etl::declval<U>(), etl::declval<TArgs>()...));
187
188 template <typename>
189 static void test(...);
190
191 using type = decltype(test<TFunction>(0));
192 };
193
194 //*******************************************
195 // Result type of a valid invocation.
196 template <typename TFunction, typename... TArgs>
197 struct invoke_result_impl<TFunction, etl::type_list<TArgs...>>
198 {
199 template <typename U>
200 static auto test(int) -> decltype(etl::invoke(etl::declval<U>(), etl::declval<TArgs>()...));
201
202 template <typename>
203 static void test(...);
204
205 using type = decltype(test<TFunction>(0));
206 };
207
208 template <typename TFunction, typename... TArgs>
209 using invoke_result_impl_t = typename invoke_result_impl<TFunction, TArgs...>::type;
210
211 //*******************************************
212 // Unwrap reference_wrapper<T> to its underlying type T&,
213 // forwarding to etl::unwrap_ref_decay for reference_wrapper detection.
214 template <typename TFunction, bool = etl::is_reference_wrapper<etl::decay_t<TFunction>>::value>
215 struct unwrap_ref_callable
216 {
217 using type = TFunction;
218 };
219
220 template <typename TFunction>
221 struct unwrap_ref_callable<TFunction, true>
222 {
223 using type = etl::unwrap_ref_decay_t<TFunction>;
224 };
225
226 template <typename TFunction>
227 using unwrap_ref_callable_t = typename unwrap_ref_callable<TFunction>::type;
228
229 //*******************************************
230 // Map raw function type to pointer, and unwrap reference_wrapper
231 // so that function_traits sees the actual callable type.
232 template <typename TFunction>
233 using effective_callable_t = etl::conditional_t< etl::is_function<etl::remove_reference_t<TFunction>>::value,
234 etl::add_pointer_t<etl::remove_reference_t<TFunction>>, unwrap_ref_callable_t<TFunction>>;
235 } // namespace private_invoke
236
237 //****************************************************************************
239 template <typename TFunction, typename, typename... TArgs>
240 struct invoke_result
241 {
242 using type = void;
243 };
244
245 //*******************************************
246 template <typename TFunction, typename... TArgs>
247 struct invoke_result< TFunction, etl::void_t<decltype(etl::invoke(etl::declval<TFunction>(), etl::declval<TArgs>()...))>, TArgs...>
248 {
249 private:
250
251 using FC = private_invoke::effective_callable_t<TFunction>;
252
253 public:
254
255 using type = etl::conditional_t<private_invoke::is_invocable_expr<FC, TArgs...>::value, private_invoke::invoke_result_impl_t<FC, TArgs...>, void>;
256 };
257
258 //****************************************************************************
260 template <typename TFunction, typename... TArgs>
261 struct invoke_result<TFunction, etl::type_list<TArgs...>>
262 {
263 private:
264
265 using FC = private_invoke::effective_callable_t<TFunction>;
266
267 public:
268
269 using type = etl::conditional_t<private_invoke::is_invocable_expr<FC, TArgs...>::value, private_invoke::invoke_result_impl_t<FC, TArgs...>, void>;
270 };
271
272 //*******************************************
273 // Specialization to allow `etl::type_list<...>` as the second template
274 // parameter.
275 template <typename TFunction, typename... TArgs>
276 struct invoke_result< TFunction, etl::void_t<decltype(etl::invoke(etl::declval<TFunction>(), etl::declval<TArgs>()...))>, etl::type_list<TArgs...>>
277 {
278 using type = decltype(etl::invoke(etl::declval<TFunction>(), etl::declval<TArgs>()...));
279 };
280
281 //*******************************************
282 template <typename TFunction, typename... TArgs>
283 using invoke_result_t = typename invoke_result<TFunction, void, TArgs...>::type;
284
285 //****************************************************************************
287 template <typename TFunction, typename... TArgs>
288 struct is_invocable : etl::bool_constant< private_invoke::is_invocable_expr< private_invoke::effective_callable_t<TFunction>, TArgs...>::value>
289 {
290 };
291
292 //****************************************************************************
293 // Specialization to allow `etl::type_list<...>` as the second template
294 // parameter.
295 template <typename TFunction, typename... TArgs>
296 struct is_invocable<TFunction, etl::type_list<TArgs...>> : is_invocable<TFunction, TArgs...>
297 {
298 };
299
300 //****************************************************************************
301 // is_invocable_r<TReturn, TFunction, TArgs...>
302 template <typename TReturn, typename TFunction, typename... TArgs>
303 struct is_invocable_r
304 : etl::conditional_t<
305 etl::is_same<TReturn, void>::value, etl::is_invocable<TFunction, TArgs...>,
306 etl::conditional_t< is_invocable<TFunction, TArgs...>::value,
307 etl::bool_constant<etl::is_convertible< invoke_result_t<TFunction, TArgs...>, TReturn>::value>, etl::false_type>>
308 {
309 };
310
311 //****************************************************************************
312 // Specialization to allow `etl::type_list<...>` as the second template
313 // parameter.
314 template <typename TReturn, typename TFunction, typename... TArgs>
315 struct is_invocable_r<TReturn, TFunction, etl::type_list<TArgs...>> : is_invocable_r<TReturn, TFunction, TArgs...>
316 {
317 };
318
319 //****************************************************************************
320 // Specialization to allow `etl::type_list<...>` when there is a preceding
321 // object argument.
322 template <typename TFunction, typename TObject, typename... TArgs>
323 struct is_invocable<TFunction, TObject, etl::type_list<TArgs...>> : is_invocable<TFunction, TObject, TArgs...>
324 {
325 };
326
327 //****************************************************************************
328 // Specialization for is_invocable_r with a preceding object argument.
329 template <typename TReturn, typename TFunction, typename TObject, typename... TArgs>
330 struct is_invocable_r<TReturn, TFunction, TObject, etl::type_list<TArgs...>> : is_invocable_r<TReturn, TFunction, TObject, TArgs...>
331 {
332 };
333
334 #if ETL_USING_CPP17
335 //****************************************************************************
337 template <typename TFunction, typename... TArgs>
338 struct is_nothrow_invocable
339 : etl::bool_constant< etl::is_invocable<TFunction, TArgs...>::value
340 && etl::function_traits< private_invoke::effective_callable_t<TFunction>>::is_noexcept>
341 {
342 };
343
344 //****************************************************************************
346 template <typename TReturn, typename TFunction, typename... TArgs>
347 struct is_nothrow_invocable_r
348 : etl::bool_constant< etl::is_invocable_r<TReturn, TFunction, TArgs...>::value
349 && etl::function_traits< private_invoke::effective_callable_t<TFunction>>::is_noexcept
350 && (etl::is_same<TReturn, void>::value
351 || etl::is_nothrow_convertible<invoke_result_t<TFunction, TArgs...>, TReturn>::value)>
352 {
353 };
354
355 //****************************************************************************
357 template <typename TReturn, typename TFunction, typename... TArgs>
358 struct is_nothrow_invocable_r<TReturn, TFunction, etl::type_list<TArgs...>>
359 : etl::bool_constant< etl::is_invocable_r<TReturn, TFunction, TArgs...>::value
360 && etl::function_traits< private_invoke::effective_callable_t<TFunction>>::is_noexcept
361 && (etl::is_same<TReturn, void>::value
362 || etl::is_nothrow_convertible<invoke_result_t<TFunction, TArgs...>, TReturn>::value)>
363 {
364 };
365
366 //****************************************************************************
367 // Specialization to allow `etl::type_list<...>` when there is a preceding
368 // object argument for the nothrow-with-return trait.
369 template <typename TReturn, typename TFunction, typename TObject, typename... TArgs>
370 struct is_nothrow_invocable_r<TReturn, TFunction, TObject, etl::type_list<TArgs...>> : is_nothrow_invocable_r<TReturn, TFunction, TObject, TArgs...>
371 {
372 };
373 #endif
374
375 #if ETL_USING_CPP17
376 template <typename TFunction, typename... TArgs>
377 inline constexpr bool is_invocable_v = is_invocable<TFunction, TArgs...>::value;
378
379 template <typename TReturn, typename TFunction, typename... TArgs>
380 inline constexpr bool is_invocable_r_v = is_invocable_r<TReturn, TFunction, TArgs...>::value;
381
382 template <typename TFunction, typename... TArgs>
383 inline constexpr bool is_nothrow_invocable_v = is_nothrow_invocable<TFunction, TArgs...>::value;
384
385 template <typename TFunction, typename... TArgs>
386 inline constexpr bool is_nothrow_invocable_r_v = is_nothrow_invocable_r<TFunction, TArgs...>::value;
387 #endif
388} // namespace etl
389
390#endif // ETL_USING_CPP11
391#endif // ETL_INVOKE_INCLUDED
bitset_ext
Definition absolute.h:40
integral_constant< bool, false > false_type
integral_constant specialisations
Definition type_traits.h:80
Definition functional.h:164