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 * This header exists because STL headers in Android doesn't define STL concepts (other than same_as which is weird),
17 * despite the fact that in `<concepts>` the synopsis contains all of them (but only as a comment).
18 * @file
19 * However, <type_traits> seems to be implemented properly so many concepts here will be just encapsulating equivalent
20 * type traits (like CConstType = std::is_const_v<T>).
21 * Using MSVC implementation as reference
22 */
23
24#if !defined(__cpp_concepts) || !__cpp_concepts
25#error "This code requires C++20 concepts support"
26#endif
27
28#include <type_traits>
29#include "CoreMinimal.h"
30
31#define MCRO_THIS_TYPE decltype(Mcro::Concepts::DecayPtr(this))
32
34{
35 //// Concepts ported from STL
36
37 template<typename A, typename B>
38 concept CSameAs = std::is_same_v<A, B>;
39
40 template<typename A, typename B>
41 concept CSameAsDecayed = std::is_same_v<std::decay_t<A>, std::decay_t<B>>;
42
43 template<typename From, typename To>
44 concept CConvertibleTo = std::is_convertible_v<From, To>;
45
46 template<typename From, typename To>
47 concept CConvertibleToDecayed = std::is_convertible_v<std::decay_t<From>, std::decay_t<To>>;
48
49 template<typename Left, typename Right>
50 concept CAssignableFrom = std::is_assignable_v<Left, Right>;
51
52 template<typename Left, typename Right>
53 concept CAssignableFromDecayed = std::is_assignable_v<std::decay_t<Left>, std::decay_t<Right>>;
54
55 template<typename Derivative, typename Base>
56 concept CDerivedFrom =
57 std::is_base_of_v<
58 std::remove_pointer_t<std::decay_t<Base>>,
59 std::remove_pointer_t<std::decay_t<Derivative>>
60 >
61 && CConvertibleTo<const volatile std::decay_t<Derivative>*, const volatile std::decay_t<Base>*>
62 ;
63
64 template<typename T>
65 concept CIntegral = std::is_integral_v<std::decay_t<T>>;
66
67 template<typename T>
68 concept CSignedIntegral = CIntegral<T> && std::is_signed_v<std::decay_t<T>>;
69
70 template<typename T>
71 concept CUnsignedIntegral = CIntegral<T> && !std::is_signed_v<std::decay_t<T>>;
72
73 template<typename T>
74 concept CFloatingPoint = std::is_floating_point_v<std::decay_t<T>>;
75
76 template<typename T>
78
79 template<typename T>
81 && requires(T&& t)
82 {
83 { !Forward<T>(t) } -> CConvertibleTo<bool>;
84 }
85 ;
86
87 template<typename T>
88 concept CPlainEnum = std::is_enum_v<std::decay_t<T>>;
89
90 template<typename T>
91 concept CScopedEnum = std::is_scoped_enum_v<std::decay_t<T>>;
92
93 template<typename T>
95
96 template<typename A, typename B>
98 requires(const std::remove_reference_t<A>& a, const std::remove_reference_t<B>& b)
99 {
100 { a == b } -> CBooleanTestable;
101 { a != b } -> CBooleanTestable;
102 }
103 ;
104
105 template<typename A, typename B>
107
108 template<typename T>
110
111 template<typename A, typename B>
112 concept CHalfOrdered = requires(const std::remove_reference_t<A>& a, const std::remove_reference_t<B>& b)
113 {
114 { a < b } -> CBooleanTestable;
115 { a > b } -> CBooleanTestable;
116 { a <= b } -> CBooleanTestable;
117 { a >= b } -> CBooleanTestable;
118 };
119
120 template<typename A, typename B>
122
123 template<typename T>
125
126 template<typename T>
127 concept CConstType = std::is_const_v<T>;
128
129 template<typename T>
130 concept CMutableType = !std::is_const_v<T>;
131
132 template<typename T>
133 concept CDestructible = std::is_nothrow_destructible_v<std::decay_t<T>>;
134
135 template<typename T, typename... From>
136 concept CConstructibleFrom = requires(From&&... from) { std::decay_t<T>(Forward<From>(from)...); };
137
138 template<typename T>
139 concept CDefaultInitializable = CConstructibleFrom<T> && requires { std::decay_t<T>{}; };
140
141 template<typename T>
143
144 template<typename T>
149 ;
150
151 template<typename T>
152 concept CMovable = std::is_object_v<T>
156 ;
157
158 template<typename T>
160 && CMovable<T>
164 ;
165
166 template<typename T>
168
169 template<typename T>
171
172 template<typename Function, typename... Args>
173 concept CInvocable = requires(std::decay_t<Function>&& function, Args&&... args)
174 {
175 std::invoke(Forward<std::decay_t<Function>&&>(function), Forward<Args&&>(args)...);
176 };
177
178 template<typename Function, typename... Args>
179 concept CPredicate = CInvocable<Function, Args...> && CBooleanTestable<std::invoke_result_t<Function, Args...>>;
180
181 template<typename Function, typename A, typename B>
182 concept CRelation =
187 ;
188
189 template<typename Function, typename A, typename B>
191
192 template<typename Function, typename A, typename B>
194
195 /** Use Unreal's own Concept templating constraint as a C++20 concept */
196 template<typename Concept, typename... Args>
197 concept CModels = TModels_V<Concept, Args...>;
198
199 //// TSharedPtr, TSharedRef and TWeakPtr concepts
200
201 template<typename T>
203
204 template<typename T>
206
207 template<typename T>
209
210 template<typename T>
212
213 template<typename T>
215
216 template<typename T>
217 concept CSharedFromThis = requires(std::decay_t<T>& t) { { t.AsShared() } -> CSharedRefOrPtr; };
218
219 //// UClasses constraining concepts
220
221 template<typename T>
223
224 template<typename T>
225 concept CInterface = TIsIInterface<std::decay_t<T>>::Value > 0;
226
227 template<typename T>
229
230 //// String/Text concepts
231
232 template<typename T>
234
235 template<typename T>
237
238 template<typename T>
240
241 template<typename T>
242 concept CNonChar = !CChar<T>;
243
244 //// Simople objects
245
246 template <typename T>
247 concept CPointer = std::is_pointer_v<std::decay_t<T>>;
248
249 template <typename T>
250 concept CClass = std::is_class_v<std::decay_t<T>>;
251
252 template <typename T>
253 concept CUnion = std::is_union_v<std::decay_t<T>>;
254
255 template <typename T>
257 && !CUObject<T>
259 ;
260
261 //// Is member pointer
262
263 namespace Detail
264 {
265 template<typename T>
267
268 // Given a pointer to a member, extract the class type (e.g. "int MyClass::*" -> Type will contain "MyClass")
269 template<typename ClassType, typename MemberType>
270 struct TExtractClassName<MemberType ClassType::*>
271 {
272 using Type = ClassType;
273 };
274
275 // Given a pointer to a member, extract the class type (e.g. "int MyClass::*" -> returns "MyClass")
276 template<typename MemberPointer>
278 }
279
280 /**
281 * Concept that returns true if the given member pointer belongs to the class.
282 *
283 * Example:
284 * class MyClass
285 * {
286 * int myMember;
287 * }
288 *
289 * CMemberPointerOf<MyClass, &MyClass::myMember> // --> true;
290 *
291 * class MyOtherClass
292 * {
293 * }
294 *
295 * CMemberPointerOf<MyOtherClass, &MyClass::myMember> // --> false;
296 */
297 template <typename OwnerObject, typename MemberPointerType>
299 std::is_member_pointer_v<MemberPointerType>
301 ;
302
303 //// Misc
304
305 template <typename T>
306 concept CNonVoid = !std::is_void_v<T>;
307
308 template<typename T>
309 concept CRefCounted = requires(std::decay_t<T>& t)
310 {
311 t.AddRef();
312 t.Release();
313 };
314
315 template <typename T>
316 concept CRange = requires(std::decay_t<T> const& t)
317 {
318 t.begin();
319 t.end();
320 };
321
322 // use in decltype
323 template <typename T> T DecayPtr(T*);
324}
typename TExtractClassName< std::decay_t< MemberPointer > >::Type TExtractedClassName
Definition Concepts.h:277