UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
Casts.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
6#include "CoreTypes.h"
7#include "Misc/NotNull.h"
10#include "UObject/Class.h"
11#include "UObject/Object.h"
14#include "UObject/ObjectPtr.h"
15#include <type_traits>
16
17#define UE_USE_CAST_FLAGS (USTRUCT_FAST_ISCHILDOF_IMPL != USTRUCT_ISCHILDOF_STRUCTARRAY)
18
19#ifndef UE_ENABLE_UNRELATED_CAST_WARNINGS
20#define UE_ENABLE_UNRELATED_CAST_WARNINGS 1
21#endif
22
23class AActor;
24class APawn;
26class FField;
28class UBlueprint;
29class ULevel;
30class UPrimitiveComponent;
31class USceneComponent;
32class USkeletalMeshComponent;
34class UStaticMeshComponent;
36template<class TClass> class TSubclassOf;
38
39[[noreturn]] COREUOBJECT_API void CastLogError(const TCHAR* FromType, const TCHAR* ToType);
40
50template <typename T, bool bIsAUObject_IMPL = std::is_convertible_v<T*, const volatile UObject*>>
52{
53 enum { Value = false };
54};
55
56template <typename T>
58{
59 template <typename U> static char (&Resolve(typename U::UClassType*))[(U::UClassType::StaticClassFlags & CLASS_Interface) ? 2 : 1];
60 template <typename U> static char (&Resolve(...))[1];
61
62 enum { Value = sizeof(Resolve<T>(0)) - 1 };
63};
64
65template <typename T>
66inline FString GetTypeName()
67{
68 if constexpr (TIsIInterface<T>::Value)
69 {
70 return T::UClassType::StaticClass()->GetName();
71 }
72 else
73 {
74 return T::StaticClass()->GetName();
75 }
76}
77
79{
80 template <typename Type>
82
83 template <typename Type>
85}
86
87template <typename Type>
88struct UE_DEPRECATED(5.5, "TCastFlags has been deprecated - use Cast instead.") TCastFlags
89{
90 static const EClassCastFlags Value = UE::CoreUObject::Private::TCastFlags_V<Type>;
91};
92
93// Dynamically cast an object type-safely.
94template <typename To, typename From>
96{
97 static_assert(sizeof(From) > 0 && sizeof(To) > 0, "Attempting to cast between incomplete types");
98
99 if (Src)
100 {
101 if constexpr (TIsIInterface<From>::Value)
102 {
103 if (UObject* Obj = Src->_getUObject())
104 {
105 if constexpr (TIsIInterface<To>::Value)
106 {
107 return (To*)Obj->GetInterfaceAddress(To::UClassType::StaticClass());
108 }
109 else
110 {
111 if constexpr (std::is_same_v<To, UObject>)
112 {
113 return Obj;
114 }
115 else
116 {
117 if (Obj->IsA<To>())
118 {
119 return (To*)Obj;
120 }
121 }
122 }
123 }
124 }
125 else
126 {
127 static_assert(std::is_base_of_v<UObjectBase, From>, "Attempting to use Cast<> on a type that is not a UObject or an Interface");
128
129 if constexpr (UE_USE_CAST_FLAGS && UE::CoreUObject::Private::TCastFlags_V<To> != CASTCLASS_None)
130 {
131 if constexpr (std::is_base_of_v<To, From>)
132 {
133 return (To*)Src;
134 }
135 else
136 {
137#if UE_ENABLE_UNRELATED_CAST_WARNINGS
138 UE_STATIC_ASSERT_WARN((std::is_base_of_v<From, To>), "Attempting to use Cast<> on types that are not related");
139#endif
140 if (((const UObject*)Src)->GetClass()->HasAnyCastFlag(UE::CoreUObject::Private::TCastFlags_V<To>))
141 {
142 return (To*)Src;
143 }
144 }
145 }
146 else
147 {
148 if constexpr (TIsIInterface<To>::Value)
149 {
150 return (To*)((UObject*)Src)->GetInterfaceAddress(To::UClassType::StaticClass());
151 }
152 else if constexpr (std::is_base_of_v<To, From>)
153 {
154 return Src;
155 }
156 else
157 {
158#if UE_ENABLE_UNRELATED_CAST_WARNINGS
159 UE_STATIC_ASSERT_WARN((std::is_base_of_v<From, To>), "Attempting to use Cast<> on types that are not related");
160#endif
161 if (((const UObject*)Src)->IsA<To>())
162 {
163 return (To*)Src;
164 }
165 }
166 }
167 }
168 }
169
170 return nullptr;
171}
172
173template <typename To, typename From>
175{
176 return Src && (Src->GetClass() == To::StaticClass()) ? (To*)Src : nullptr;
177}
178
179#if DO_CHECK
180
181 // Helper function to get the full name for UObjects and UInterfaces
182 template <typename T>
184 {
185 // A special version for FFields
186 if constexpr (std::is_base_of_v<FField, T>)
187 {
189 }
190 else if constexpr (std::is_base_of_v<UObject, T>)
191 {
192 return InObjectOrInterface->GetFullName();;
193 }
194 else
195 {
196 return Cast<UObject>(InObjectOrInterface)->GetFullName();
197 }
198 }
199
200 template <typename To, typename From>
204 {
205 static_assert(sizeof(From) > 0 && sizeof(To) > 0, "Attempting to cast between incomplete types");
206
207 if (!Src)
208 {
209 CastLogError(TEXT("nullptr"), *GetTypeName<To>());
210 }
211
213 if (!Result)
214 {
216 }
217
218 return Result;
219 }
220
221 template <typename To, typename From>
223 {
224 static_assert(sizeof(From) > 0 && sizeof(To) > 0, "Attempting to cast between incomplete types");
225
226 if (Src)
227 {
229 if (!Result)
230 {
232 }
233
234 return Result;
235 }
236
238 {
239 CastLogError(TEXT("nullptr"), *GetTypeName<To>());
240 }
241
242 return nullptr;
243 }
244
245#else
246
247 template <typename To, typename From>
251 {
252 static_assert(sizeof(From) > 0 && sizeof(To) > 0, "Attempting to cast between incomplete types");
253
254 if constexpr (TIsIInterface<From>::Value)
255 {
256 UObject* Obj = Src->_getUObject();
257 if constexpr (TIsIInterface<To>::Value)
258 {
259 return (To*)Obj->GetInterfaceAddress(To::UClassType::StaticClass());
260 }
261 else
262 {
263 return (To*)Obj;
264 }
265 }
266 else
267 {
268 static_assert(std::is_base_of_v<UObjectBase, From>, "Attempting to use Cast<> on a type that is not a UObject or an Interface");
269
270 if constexpr (TIsIInterface<To>::Value)
271 {
272 return (To*)((UObject*)Src)->GetInterfaceAddress(To::UClassType::StaticClass());
273 }
274 else
275 {
276 return (To*)Src;
277 }
278 }
279 }
280
281 template <typename To, typename From>
286
287#endif
288
289// auto weak versions
290template <typename To, typename From>
295template <typename To, typename From>
300template <typename To, typename From>
305template <typename To, typename From>
310
311// object ptr versions
312template <typename To, typename From>
314{
315 static_assert(sizeof(To) > 0 && sizeof(From) > 0, "Attempting to cast between incomplete types");
316
317 const FObjectPtr& Src = (const FObjectPtr&)InSrc;
318
319 if constexpr (UE_USE_CAST_FLAGS && UE::CoreUObject::Private::TCastFlags_V<To> != CASTCLASS_None)
320 {
321 if (Src)
322 {
323 if constexpr (std::is_base_of_v<To, From>)
324 {
325 return (To*)Src.Get();
326 }
327 else
328 {
329 #if UE_ENABLE_UNRELATED_CAST_WARNINGS
330 UE_STATIC_ASSERT_WARN((std::is_base_of_v<From, To>), "Attempting to use Cast<> on types that are not related");
331 #endif
332 if (Src.GetClass()->HasAnyCastFlag(UE::CoreUObject::Private::TCastFlags_V<To>))
333 {
334 return (To*)Src.Get();
335 }
336 }
337 }
338 }
339 else if constexpr (TIsIInterface<To>::Value)
340 {
342 if (SrcObj)
343 {
345 return (To*)Src.Get()->GetInterfaceAddress(To::UClassType::StaticClass());
346 }
347 }
348 else if constexpr (std::is_base_of_v<To, From>)
349 {
350 if (Src)
351 {
352 return (To*)Src.Get();
353 }
354 }
355 else
356 {
357#if UE_ENABLE_UNRELATED_CAST_WARNINGS
358 UE_STATIC_ASSERT_WARN((std::is_base_of_v<From, To>), "Attempting to use Cast<> on types that are not related");
359#endif
360 if (Src && Src.IsA<To>())
361 {
362 return (To*)Src.Get();
363 }
364 }
365
366 return nullptr;
367}
368
369template <typename To, typename From>
371{
372 static_assert(sizeof(To) > 0, "Attempting to cast to an incomplete type");
373
375 if (SrcObj && (SrcObj->GetClass() == To::StaticClass()))
376 {
378 return (To*)SrcObj;
379 }
380 return nullptr;
381}
382
383template <typename To, typename From>
385{
386 static_assert(sizeof(From) > 0 && sizeof(To) > 0, "Attempting to cast between incomplete types");
387
388#if DO_CHECK
389 if (Src)
390 {
391 auto* Result = Cast<To>(Src);
392 if (!Result)
393 {
395 }
396
397 return Result;
398}
399
401 {
402 CastLogError(TEXT("nullptr"), *GetTypeName<To>());
403 }
404
405 return nullptr;
406#else
407 if constexpr (UE_USE_CAST_FLAGS && UE::CoreUObject::Private::TCastFlags_V<To> != CASTCLASS_None)
408 {
409 return (To*)((const FObjectPtr&)Src).Get();
410 }
411 else if constexpr (TIsIInterface<To>::Value)
412 {
415 return (To*)((const FObjectPtr&)Src).Get()->GetInterfaceAddress(To::UClassType::StaticClass());
416 }
417 else
418 {
419 return (To*)((const FObjectPtr&)Src).Get();
420 }
421#endif
422}
423
424// TSubclassOf versions
425template <typename To, typename From>
430template <typename To, typename From>
435template <typename To, typename From>
440
441// TNotNull versions of the casts
442#if UE_ENABLE_NOTNULL_WRAPPER
443 template <typename T, typename U>
444 UE_FORCEINLINE_HINT auto Cast(TNotNull<U> Ptr) -> decltype(Cast<T>((U)Ptr))
445 {
446 return Cast<T>((U)Ptr);
447 }
448 template <typename T, typename U>
449 UE_FORCEINLINE_HINT auto ExactCast(TNotNull<U> Ptr) -> decltype(ExactCast<T>((U)Ptr))
450 {
451 return ExactCast<T>((U)Ptr);
452 }
453 template <typename T, typename U>
454 UE_FORCEINLINE_HINT auto CastChecked(TNotNull<U> Ptr) -> decltype(CastChecked<T>((U)Ptr))
455 {
456 return CastChecked<T>((U)Ptr);
457 }
458 template <typename T, typename U>
460 {
461 return CastChecked<T>((U)Ptr, CheckType);
462 }
463#endif
464
465#define DECLARE_CAST_BY_FLAG(ClassName) \
466 class ClassName; \
467 template <> \
468 constexpr inline EClassCastFlags UE::CoreUObject::Private::TCastFlags_V<ClassName> = CASTCLASS_##ClassName;
469
504DECLARE_CAST_BY_FLAG(USceneComponent)
505DECLARE_CAST_BY_FLAG(UPrimitiveComponent)
507DECLARE_CAST_BY_FLAG(USkeletalMeshComponent)
510DECLARE_CAST_BY_FLAG(UStaticMeshComponent)
528
529#undef DECLARE_CAST_BY_FLAG
530
532{
533 template <typename T>
535 {
536 // It's from-castable if it's an interface or a UObject-derived type
537 enum { Value = TIsIInterface<T>::Value || std::is_convertible_v<T*, const volatile UObject*> };
538 };
539
540 template <typename To, typename From>
541 inline To DynamicCast(From* Arg)
542 {
543 using ToValueType = std::remove_pointer_t<To>;
544
545 if constexpr (!std::is_pointer_v<To> || !TIsCastable<From>::Value || !TIsCastable<ToValueType>::Value)
546 {
547 return dynamic_cast<To>(Arg);
548 }
549 else
550 {
551 // Casting away const/volatile
552 static_assert(!TLosesQualifiersFromTo_V<From, ToValueType>, "Conversion loses qualifiers");
553
554 if constexpr (std::is_void_v<ToValueType>)
555 {
556 // When casting to void, cast to UObject instead and let it implicitly cast to void
557 return Cast<UObject>(Arg);
558 }
559 else
560 {
561 return Cast<ToValueType>(Arg);
562 }
563 }
564 }
565
566 template <typename To, typename From>
567 inline To DynamicCast(From&& Arg)
568 {
569 using FromValueType = std::remove_reference_t<From>;
570 using ToValueType = std::remove_reference_t<To>;
571
573 {
574 // This may fail when dynamic_casting rvalue references due to patchy compiler support
575 return dynamic_cast<To>(Arg);
576 }
577 else
578 {
579 // Casting away const/volatile
580 static_assert(!TLosesQualifiersFromTo_V<FromValueType, ToValueType>, "Conversion loses qualifiers");
581
582 // T&& can only be cast to U&&
583 // http://en.cppreference.com/w/cpp/language/dynamic_cast
584 static_assert(std::is_lvalue_reference_v<From> || std::is_rvalue_reference_v<To>, "Cannot dynamic_cast from an rvalue to a non-rvalue reference");
585
587 }
588 }
589}
590
591#define dynamic_cast UE::CoreUObject::Private::DynamicCast
FString GetTypeName()
Definition Casts.h:66
FUNCTION_NON_NULL_RETURN_START TCopyQualifiersFromTo_T< From, To > * CastChecked(From *Src) FUNCTION_NON_NULL_RETURN_END
Definition Casts.h:249
#define UE_USE_CAST_FLAGS
Definition Casts.h:17
TCopyQualifiersFromTo_T< From, To > * Cast(From *Src)
Definition Casts.h:95
COREUOBJECT_API void CastLogError(const TCHAR *FromType, const TCHAR *ToType)
Definition Casts.cpp:8
UE_FORCEINLINE_HINT TCopyQualifiersFromTo_T< From, To > * ExactCast(From *Src)
Definition Casts.h:174
#define DECLARE_CAST_BY_FLAG(ClassName)
Definition Casts.h:465
typename TCopyQualifiersFromTo< From, To >::Type TCopyQualifiersFromTo_T
Definition CopyQualifiersFromTo.h:17
#define UE_STATIC_ASSERT_WARN(bExpression, Message)
Definition CoreMiscDefines.h:431
#define UE_DEPRECATED(Version, Message)
Definition CoreMiscDefines.h:302
FString GetFullNameSafe(const FField *InField)
Definition Field.cpp:1138
#define TEXT(x)
Definition Platform.h:1272
FPlatformTypes::TCHAR TCHAR
Either ANSICHAR or WIDECHAR, depending on whether the platform supports wide characters or the requir...
Definition Platform.h:1135
#define UE_FORCEINLINE_HINT
Definition Platform.h:723
#define FUNCTION_NON_NULL_RETURN_END
Definition Platform.h:807
#define FUNCTION_NON_NULL_RETURN_START
Definition Platform.h:804
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
T TNotNull
Definition NotNull.h:307
EClassCastFlags
Definition ObjectMacros.h:333
@ CASTCLASS_None
Definition ObjectMacros.h:334
@ CLASS_Interface
Definition ObjectMacros.h:234
Definition Actor.h:257
Definition PlayerController.h:261
Definition UnrealType.h:3702
Definition UnrealType.h:2543
Definition UnrealType.h:2167
Definition UnrealType.h:3411
Definition UnrealType.h:6397
Definition UnrealType.h:2503
Definition EnumProperty.h:29
Definition Field.h:556
Definition UnrealType.h:2465
Definition UnrealType.h:2271
Definition UnrealType.h:2336
Definition UnrealType.h:2239
Definition UnrealType.h:2304
Definition UnrealType.h:3561
Definition UnrealType.h:3269
Definition UnrealType.h:3843
Definition UnrealType.h:6464
Definition UnrealType.h:6593
Definition UnrealType.h:6643
Definition UnrealType.h:3649
Definition UnrealType.h:1766
Definition UnrealType.h:2725
Definition UnrealType.h:3087
Definition PropertyOptional.h:185
Definition UnrealType.h:174
Definition UnrealType.h:4028
Definition UnrealType.h:3488
Definition UnrealType.h:3331
Definition UnrealType.h:6306
Definition TextProperty.h:21
Definition UnrealType.h:2368
Definition UnrealType.h:2400
Definition UnrealType.h:2432
Definition UnrealType.h:3204
Definition SubclassOf.h:30
Definition Blueprint.h:403
Definition Class.h:3793
UE_FORCEINLINE_HINT bool HasAnyCastFlag(EClassCastFlags FlagToCheck) const
Definition Class.h:4546
Definition Class.h:2681
Definition Class.h:2791
Definition Class.h:181
Definition Class.h:2476
Definition Level.h:423
COREUOBJECT_API void * GetInterfaceAddress(UClass *InterfaceClass)
Definition UObjectBaseUtility.cpp:466
Definition Object.h:95
Definition Package.h:216
Definition Class.h:1720
Definition SkinnedMeshComponent.h:258
Definition Class.h:2710
Definition Class.h:480
Type
Definition Object.h:60
@ NullChecked
Definition Object.h:64
Definition CoreGlobals.cpp:268
UObject * ResolveObjectHandleNoRead(FObjectHandle &Handle)
Definition ObjectHandle.h:502
constexpr EClassCastFlags TCastFlags_V
Definition Casts.h:81
constexpr EClassCastFlags TCastFlags_V< const Type >
Definition Casts.h:84
To DynamicCast(From *Arg)
Definition Casts.h:541
void OnHandleRead(const UObject *Object)
Definition ObjectHandleTracking.h:131
UE_STRING_CLASS Result(Forward< LhsType >(Lhs), RhsLen)
Definition String.cpp.inl:732
@ false
Definition radaudio_common.h:23
Definition ObjectPtr.h:55
FORCEINLINE UObject * Get() const
Definition ObjectPtr.h:104
FORCEINLINE FObjectHandle & GetHandleRef() const
Definition ObjectPtr.h:272
COREUOBJECT_API bool IsA(const UClass *SomeBase) const
Definition ObjectPtr.cpp:252
FORCEINLINE UClass * GetClass() const
Definition ObjectPtr.h:109
static char(& Resolve(typename U::UClassType *))[(U::UClassType::StaticClassFlags &CLASS_Interface) ? 2 :1]
static char(& Resolve(...))[1]
Definition Casts.h:52
@ Value
Definition Casts.h:53
Definition ObjectPtr.h:488
FORCEINLINE T * Get() const
Definition ObjectPtr.h:664
Definition WeakObjectPtrTemplates.h:25
FORCEINLINE T * Get(bool bEvenIfPendingKill) const
Definition WeakObjectPtrTemplates.h:132