MCRO
C++23 utilities for Unreal Engine.
Loading...
Searching...
No Matches
Concepts.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 * @brief
17 * This header exists because STL headers in Android doesn't define STL concepts (other than same_as which is weird),
18 * despite the fact that in `<concepts>` the synopsis contains all of them (but only as a comment).
19 * @file
20 * However, <type_traits> seems to be implemented properly so many concepts here will be just encapsulating equivalent
21 * type traits (like CConstType = std::is_const_v<T>).
22 * Using MSVC implementation as reference
23 */
24
25#if !defined(__cpp_concepts) || !__cpp_concepts
26#error "This code requires C++20 concepts support"
27#endif
28
29#include <type_traits>
30#include "CoreMinimal.h"
31#include "Templates/Casts.h"
32#include "UObject/Interface.h"
33#include "Mcro/Macros.h"
34
35#define MCRO_THIS_TYPE decltype(Mcro::Concepts::DecayPtr(this))
36
38{
39 //// Concepts ported from STL
40
41 template<typename A, typename B>
42 concept CSameAs = std::is_same_v<A, B>;
43
44 template<typename A, typename B>
45 concept CSameAsDecayed = std::is_same_v<std::decay_t<A>, std::decay_t<B>>;
46
47 template<typename From, typename To>
48 concept CConvertibleTo = std::is_convertible_v<From, To>;
49
50 template<typename From, typename To>
51 concept CConvertibleToDecayed = std::is_convertible_v<std::decay_t<From>, std::decay_t<To>>;
52
53 template<typename Left, typename Right>
54 concept CAssignableFrom = std::is_assignable_v<Left, Right>;
55
56 template<typename Left, typename Right>
57 concept CAssignableFromDecayed = std::is_assignable_v<std::decay_t<Left>, std::decay_t<Right>>;
58
59 template<typename Derivative, typename Base>
60 concept CDerivedFrom =
61 std::is_base_of_v<
62 std::remove_pointer_t<std::decay_t<Base>>,
63 std::remove_pointer_t<std::decay_t<Derivative>>
64 >
65 && CConvertibleTo<const volatile std::decay_t<Derivative>*, const volatile std::decay_t<Base>*>
66 ;
67
68 template<typename T>
69 concept CIntegral = std::is_integral_v<std::decay_t<T>>;
70
71 template<typename T>
72 concept CSignedIntegral = CIntegral<T> && std::is_signed_v<std::decay_t<T>>;
73
74 template<typename T>
75 concept CUnsignedIntegral = CIntegral<T> && !std::is_signed_v<std::decay_t<T>>;
76
77 template<typename T>
78 concept CFloatingPoint = std::is_floating_point_v<std::decay_t<T>>;
79
80 template<typename T>
82
83 template<typename T>
85 && requires(T&& t)
86 {
87 { !FWD(t) } -> CConvertibleTo<bool>;
88 }
89 ;
90
91 template<typename T>
92 concept CPlainEnum = std::is_enum_v<std::decay_t<T>>;
93
94 template<typename T>
95 concept CScopedEnum = std::is_scoped_enum_v<std::decay_t<T>>;
96
97 template<typename T>
99
100 template<typename A, typename B>
102 requires(const std::remove_reference_t<A>& a, const std::remove_reference_t<B>& b)
103 {
104 { a == b } -> CBooleanTestable;
105 { a != b } -> CBooleanTestable;
106 }
107 ;
108
109 template<typename A, typename B>
111
112 template<typename T>
114
115 template<typename A, typename B>
116 concept CHalfOrdered = requires(const std::remove_reference_t<A>& a, const std::remove_reference_t<B>& b)
117 {
118 { a < b } -> CBooleanTestable;
119 { a > b } -> CBooleanTestable;
120 { a <= b } -> CBooleanTestable;
121 { a >= b } -> CBooleanTestable;
122 };
123
124 template<typename A, typename B>
126
127 template<typename T>
129
130 template<typename T>
131 concept CConstType = std::is_const_v<T>;
132
133 template<typename T>
134 concept CMutableType = !std::is_const_v<T>;
135
136 template<typename T>
137 concept CDestructible = std::is_nothrow_destructible_v<std::decay_t<T>>;
138
139 template<typename T, typename... From>
140 concept CConstructibleFrom = requires(From&&... from) { std::decay_t<T>(FWD(from)...); };
141
142 template<typename T>
143 concept CDefaultInitializable = CConstructibleFrom<T> && requires { std::decay_t<T>{}; };
144
145 template<typename T>
147
148 template<typename T>
153 ;
154
155 template<typename T>
156 concept CMovable = std::is_object_v<T>
160 ;
161
162 template<typename T>
164 && CMovable<T>
168 ;
169
170 template<typename T>
172
173 template<typename T>
175
176 template<typename Function, typename... Args>
177 concept CInvocable = requires(std::decay_t<Function>&& function, Args&&... args)
178 {
179 std::invoke(FWD(function), Forward<Args&&>(args)...);
180 };
181
182 template<typename Function, typename... Args>
183 concept CPredicate = CInvocable<Function, Args...> && CBooleanTestable<std::invoke_result_t<Function, Args...>>;
184
185 template<typename Function, typename A, typename B>
186 concept CRelation =
191 ;
192
193 template<typename Function, typename A, typename B>
195
196 template<typename Function, typename A, typename B>
198
199 template <typename T>
200 concept CAbstract = std::is_abstract_v<T>;
201
202 template <typename T>
203 concept CNonAbstract = !std::is_abstract_v<T>;
204
205 /** Use Unreal's own Concept templating constraint as a C++20 concept */
206 template<typename Concept, typename... Args>
207 concept CModels = TModels_V<Concept, Args...>;
208
209 //// TSharedPtr, TSharedRef and TWeakPtr concepts
210
211 template<typename T>
213
214 template<typename T>
216
217 template<typename T>
219
220 template<typename T>
222
223 template<typename T>
225
226 template<typename T>
227 concept CSharedFromThis = requires(std::decay_t<T>& t) { { t.AsShared() } -> CSharedRefOrPtr; };
228
229 template<typename T, typename ElementType>
231
232 template<typename T, typename ElementType>
234
235 template<typename T, typename ElementType>
237
238 template<typename T, typename ElementType>
240
241 template<typename T, typename ElementType>
243
244 template<typename T, typename ElementType>
245 concept CSharedFromThisOf = requires(std::decay_t<T>& t) { { t.AsShared() } -> CSharedRefOrPtrOf<ElementType>; };
246
247 //// UClasses constraining concepts
248
249 template<typename T>
251
252 template<typename T>
253 concept CInterface = TIsIInterface<std::decay_t<T>>::Value > 0;
254
255 template<typename T>
257
258 template<typename T>
260
261 //// String/Text concepts
262
263 template<typename T>
265
266 template<typename T>
268
269 template<typename T>
271
272 template<typename T>
274
275 template<typename T>
276 concept CChar =
277 CSameAs<std::decay_t<T>, UTF8CHAR>
278 || CSameAs<std::decay_t<T>, UTF16CHAR>
279 || CSameAs<std::decay_t<T>, UTF32CHAR>
280 || CSameAs<std::decay_t<T>, WIDECHAR>
281 || CSameAs<std::decay_t<T>, UCS2CHAR>
282 || CSameAs<std::decay_t<T>, ANSICHAR>
283 ;
284
285 template<typename T>
286 concept CNonChar = !CChar<T>;
287
288 template<typename T>
290
291 template<typename T>
293
294 //// Simple objects
295
296 template <typename T>
297 concept CPointer = std::is_pointer_v<std::decay_t<T>>;
298
299 template <typename T>
300 concept CClass = std::is_class_v<std::decay_t<T>>;
301
302 template <typename T>
303 concept CUnion = std::is_union_v<std::decay_t<T>>;
304
305 template <typename T>
307 && !CUObject<T>
309 ;
310
311 //// Is member pointer
312
313 namespace Detail
314 {
315 template<typename T>
317
318 // Given a pointer to a member, extract the class type (e.g. "int MyClass::*" -> Type will contain "MyClass")
319 template<typename ClassType, typename MemberType>
320 struct TExtractClassName<MemberType ClassType::*>
321 {
322 using Type = ClassType;
323 };
324
325 // Given a pointer to a member, extract the class type (e.g. "int MyClass::*" -> returns "MyClass")
326 template<typename MemberPointer>
328 }
329
330 /**
331 * Concept that returns true if the given member pointer belongs to the class.
332 *
333 * Example:
334 * @code
335 * class MyClass
336 * {
337 * int myMember;
338 * };
339 *
340 * CMemberPointerOf<MyClass, &MyClass::myMember>; // --> true;
341 *
342 * class MyOtherClass {};
343 *
344 * CMemberPointerOf<MyOtherClass, &MyClass::myMember>; // --> false;
345 * @endcode
346 */
347 template <typename OwnerObject, typename MemberPointerType>
349 std::is_member_pointer_v<MemberPointerType>
351 ;
352
353 //// Misc
354
355 template <typename T>
356 concept CVoid = std::is_void_v<T>;
357
358 template <typename T>
359 concept CNonVoid = !std::is_void_v<T>;
360
361 template <typename T>
362 concept CRefCounted = requires(std::decay_t<T>& t)
363 {
364 t.AddRef();
365 t.Release();
366 };
367
368 template <typename T>
369 concept CRangeMember = requires(std::decay_t<T>&& t) { t.begin(); t.end(); };
370
371 template <typename T>
372 concept CValidableMember = requires(std::decay_t<T> t) { { t.IsValid() } -> CBooleanTestable; };
373
374 template <typename T>
375 concept CValidableAdl = requires(std::decay_t<T> t) { { IsValid(t) } -> CBooleanTestable; };
376
377 template <typename T>
379
380 /** @brief Attempt to test the input object validity through various methods. */
381 template <CValidable T>
382 bool TestValid(T&& input)
383 {
384 if constexpr (CValidableMember<T>) return input.IsValid();
385 else if constexpr (CValidableAdl<T>) return IsValid(input);
386 else return static_cast<bool>(input);
387 }
388
389 // use in decltype
390 template <typename T> T DecayPtr(T*);
391}
#define FWD(...)
Shorten forwarding expression with this macro so one may not need to specify explicit type.
Definition Macros.h:100
typename TExtractClassName< std::decay_t< MemberPointer > >::Type TExtractedClassName
Definition Concepts.h:327
bool TestValid(T &&input)
Attempt to test the input object validity through various methods.
Definition Concepts.h:382