// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "UObject/ObjectMacros.h" #include "UObject/Object.h" #include "UObject/Class.h" #include "Templates/LosesQualifiersFromTo.h" #include "Traits/IsVoidType.h" class AActor; class APawn; class APlayerController; class FSoftClassProperty; class UBlueprint; class ULevel; class UPrimitiveComponent; class USceneComponent; class USkeletalMeshComponent; class USkinnedMeshComponent; class UStaticMeshComponent; /// @cond DOXYGEN_WARNINGS template class TSubclassOf; /// @endcond UE_NORETURN COREUOBJECT_API void CastLogError(const TCHAR* FromType, const TCHAR* ToType); /** * Metafunction which detects whether or not a class is an IInterface. Rules: * * 1. A UObject is not an IInterface. * 2. A type without a UClassType typedef member is not an IInterface. * 3. A type whose UClassType::StaticClassFlags does not have CLASS_Interface set is not an IInterface. * * Otherwise, assume it's an IInterface. */ template ::Value> struct TIsIInterface { enum { Value = false }; }; template struct TIsIInterface { template static char (&Resolve(typename U::UClassType*))[(U::UClassType::StaticClassFlags & CLASS_Interface) ? 2 : 1]; template static char (&Resolve(...))[1]; enum { Value = sizeof(Resolve(0)) - 1 }; }; template struct TIsCastable { // It's from-castable if it's an interface or a UObject-derived type enum { Value = TIsIInterface::Value || TPointerIsConvertibleFromTo < T, const volatile UObject > ::Value }; }; template struct TIsCastableToPointer: TOr, TIsCastable> { // It's to-pointer-castable if it's from-castable or void }; template FORCEINLINE typename TEnableIf::Value, FString>::Type GetTypeName() { return T::UClassType::StaticClass()->GetName(); } template FORCEINLINE typename TEnableIf::Value, FString>::Type GetTypeName() { return T::StaticClass()->GetName(); } enum class ECastType { UObjectToUObject, InterfaceToUObject, UObjectToInterface, InterfaceToInterface, FromCastFlags }; template struct TCastFlags { static const EClassCastFlags Value = CASTCLASS_None; }; template ::Value, bool bToInterface = TIsIInterface::Value, EClassCastFlags CastClass = TCastFlags::Value> struct TGetCastType { #if USTRUCT_FAST_ISCHILDOF_IMPL == USTRUCT_ISCHILDOF_STRUCTARRAY static const ECastType Value = ECastType::UObjectToUObject; #else static const ECastType Value = ECastType::FromCastFlags; #endif }; template struct TGetCastType { static const ECastType Value = ECastType::UObjectToUObject; }; template struct TGetCastType { static const ECastType Value = ECastType::UObjectToInterface; }; template struct TGetCastType { static const ECastType Value = ECastType::InterfaceToUObject; }; template struct TGetCastType { static const ECastType Value = ECastType::InterfaceToInterface; }; template To* Cast(From* Src); template ::Value> struct TCastImpl { // This is the cast flags implementation FORCEINLINE static To* DoCast(UObject* Src) { return Src && Src->GetClass()->HasAnyCastFlag(TCastFlags::Value) ? (To*)Src : nullptr; } FORCEINLINE static To* DoCastCheckedWithoutTypeCheck(UObject* Src) { return (To*)Src; } UE_DEPRECATED(4.25, "Cast<>() and CastChecked<>() should not be used with FProperties. Use CastField<>() or CastFieldChecked<>() instead.") FORCEINLINE static To* DoCast(FField* Src) { return Src && Src->IsA() ? (To*)Src : nullptr; } UE_DEPRECATED(4.25, "Cast<>() and CastChecked<>() should not be used with FProperties. Use CastField<>() or CastFieldChecked<>() instead.") FORCEINLINE static To* DoCastCheckedWithoutTypeCheck(FField* Src) { return (To*)Src; } }; template struct TCastImpl { FORCEINLINE static To* DoCast(UObject* Src) { return Src && Src->IsA() ? (To*)Src : nullptr; } FORCEINLINE static To* DoCastCheckedWithoutTypeCheck(UObject* Src) { return (To*)Src; } UE_DEPRECATED(4.25, "Cast<>() and CastChecked<>() should not be used with FProperties. Use CastField<>() or CastFieldChecked<>() instead.") FORCEINLINE static To* DoCast(FField* Src) { return Src && Src->IsA() ? (To*)Src : nullptr; } UE_DEPRECATED(4.25, "Cast<>() and CastChecked<>() should not be used with FProperties. Use CastField<>() or CastFieldChecked<>() instead.") FORCEINLINE static To* DoCastCheckedWithoutTypeCheck(FField* Src) { return (To*)Src; } }; template struct TCastImpl { FORCEINLINE static To* DoCast(From* Src) { To* Result = nullptr; if (Src) { UObject* Obj = Src->_getUObject(); if (Obj->IsA()) { Result = (To*)Obj; } } return Result; } FORCEINLINE static To* DoCastCheckedWithoutTypeCheck(From* Src) { return Src ? (To*)Src->_getUObject() : nullptr; } }; template struct TCastImpl { FORCEINLINE static To* DoCast(UObject* Src) { return Src ? (To*)Src->GetInterfaceAddress(To::UClassType::StaticClass()) : nullptr; } FORCEINLINE static To* DoCastCheckedWithoutTypeCheck(UObject* Src) { return Src ? (To*)Src->GetInterfaceAddress(To::UClassType::StaticClass()) : nullptr; } }; template struct TCastImpl { FORCEINLINE static To* DoCast(From* Src) { return Src ? (To*)Src->_getUObject()->GetInterfaceAddress(To::UClassType::StaticClass()) : nullptr; } FORCEINLINE static To* DoCastCheckedWithoutTypeCheck(From* Src) { return Src ? (To*)Src->_getUObject()->GetInterfaceAddress(To::UClassType::StaticClass()) : nullptr; } }; // Dynamically cast an object type-safely. template FORCEINLINE To* Cast(From* Src) { return TCastImpl::DoCast(Src); } template FORCEINLINE T* ExactCast(UObject* Src) { return Src && (Src->GetClass() == T::StaticClass()) ? (T*)Src : nullptr; } #if DO_CHECK // Helper function to get the full name for UObjects and UInterfaces template < typename T, typename TEnableIf::Value>::Type* = nullptr> FString GetFullNameForCastLogError(T* InObjectOrInterface) { return Cast(InObjectOrInterface)->GetFullName(); } // And a special version for FFields template < typename T, typename TEnableIf::Value>::Type* = nullptr> FString GetFullNameForCastLogError(T* InField) { return GetFullNameSafe(InField); } template FUNCTION_NON_NULL_RETURN_START To* CastChecked(From* Src) FUNCTION_NON_NULL_RETURN_END { if (!Src) { CastLogError(TEXT("nullptr"), *GetTypeName()); } To* Result = Cast(Src); if (!Result) { CastLogError(*GetFullNameForCastLogError(Src), *GetTypeName()); } return Result; } template To* CastChecked(From* Src, ECastCheckedType::Type CheckType) { if (Src) { To* Result = Cast(Src); if (!Result) { CastLogError(*GetFullNameForCastLogError(Src), *GetTypeName()); } return Result; } if (CheckType == ECastCheckedType::NullChecked) { CastLogError(TEXT("nullptr"), *GetTypeName()); } return nullptr; } #else template FUNCTION_NON_NULL_RETURN_START FORCEINLINE To* CastChecked(From* Src) FUNCTION_NON_NULL_RETURN_END { return TCastImpl::DoCastCheckedWithoutTypeCheck(Src); } template FORCEINLINE To* CastChecked(From* Src, ECastCheckedType::Type CheckType) { return TCastImpl::DoCastCheckedWithoutTypeCheck(Src); } #endif // auto weak versions template FORCEINLINE T* Cast(const TWeakObjectPtr& Src) { return Cast(Src.Get()); } template FORCEINLINE T* ExactCast(const TWeakObjectPtr& Src) { return ExactCast(Src.Get()); } template FORCEINLINE T* CastChecked(const TWeakObjectPtr& Src, ECastCheckedType::Type CheckType = ECastCheckedType::NullChecked) { return CastChecked(Src.Get(), CheckType); } // TSubclassOf versions template FORCEINLINE T* Cast(const TSubclassOf& Src) { return Cast(*Src); } template FORCEINLINE T* CastChecked(const TSubclassOf& Src, ECastCheckedType::Type CheckType = ECastCheckedType::NullChecked) { return CastChecked(*Src, CheckType); } // Const versions of the casts template FORCEINLINE const T* Cast(const U* Src) { return Cast(const_cast(Src)); } template FORCEINLINE const T* ExactCast(const UObject* Src) { return ExactCast(const_cast(Src)); } template FORCEINLINE const T* CastChecked(const U* Src, ECastCheckedType::Type CheckType = ECastCheckedType::NullChecked) { return CastChecked(const_cast(Src), CheckType); } #define DECLARE_CAST_BY_FLAG_FWD(ClassName) class ClassName; #define DECLARE_CAST_BY_FLAG_CAST(ClassName) \ template <> \ struct TCastFlags \ { \ static const EClassCastFlags Value = CASTCLASS_##ClassName; \ }; \ template <> \ struct TCastFlags \ { \ static const EClassCastFlags Value = CASTCLASS_##ClassName; \ }; #define DECLARE_CAST_BY_FLAG(ClassName) \ DECLARE_CAST_BY_FLAG_FWD(ClassName) \ DECLARE_CAST_BY_FLAG_CAST(ClassName) #define FINISH_DECLARING_CAST_FLAGS // intentionally defined to do nothing. // Define a macro that declares all the cast flags. // This allows us to reuse these declarations elsewhere to define other properties for these classes. // Note: When adding an item to this list, you must also add a CASTCLASS_ flag in ObjectBase.h and rebuild UnrealHeaderTool. #define DECLARE_ALL_CAST_FLAGS \ DECLARE_CAST_BY_FLAG(UField) \ DECLARE_CAST_BY_FLAG(UEnum) \ DECLARE_CAST_BY_FLAG(UStruct) \ DECLARE_CAST_BY_FLAG(UScriptStruct) \ DECLARE_CAST_BY_FLAG(UClass) \ DECLARE_CAST_BY_FLAG(FProperty) \ DECLARE_CAST_BY_FLAG(FObjectPropertyBase) \ DECLARE_CAST_BY_FLAG(FObjectProperty) \ DECLARE_CAST_BY_FLAG(FWeakObjectProperty) \ DECLARE_CAST_BY_FLAG(FLazyObjectProperty) \ DECLARE_CAST_BY_FLAG(FSoftObjectProperty) \ DECLARE_CAST_BY_FLAG(FSoftClassProperty) \ DECLARE_CAST_BY_FLAG(FBoolProperty) \ DECLARE_CAST_BY_FLAG(UFunction) \ DECLARE_CAST_BY_FLAG(FStructProperty) \ DECLARE_CAST_BY_FLAG(FByteProperty) \ DECLARE_CAST_BY_FLAG(FIntProperty) \ DECLARE_CAST_BY_FLAG(FFloatProperty) \ DECLARE_CAST_BY_FLAG(FDoubleProperty) \ DECLARE_CAST_BY_FLAG(FClassProperty) \ DECLARE_CAST_BY_FLAG(FInterfaceProperty) \ DECLARE_CAST_BY_FLAG(FNameProperty) \ DECLARE_CAST_BY_FLAG(FStrProperty) \ DECLARE_CAST_BY_FLAG(FTextProperty) \ DECLARE_CAST_BY_FLAG(FArrayProperty) \ DECLARE_CAST_BY_FLAG(FDelegateProperty) \ DECLARE_CAST_BY_FLAG(FMulticastDelegateProperty) \ DECLARE_CAST_BY_FLAG(UPackage) \ DECLARE_CAST_BY_FLAG(ULevel) \ DECLARE_CAST_BY_FLAG(AActor) \ DECLARE_CAST_BY_FLAG(APlayerController) \ DECLARE_CAST_BY_FLAG(APawn) \ DECLARE_CAST_BY_FLAG(USceneComponent) \ DECLARE_CAST_BY_FLAG(UPrimitiveComponent) \ DECLARE_CAST_BY_FLAG(USkinnedMeshComponent) \ DECLARE_CAST_BY_FLAG(USkeletalMeshComponent) \ DECLARE_CAST_BY_FLAG(UBlueprint) \ DECLARE_CAST_BY_FLAG(UDelegateFunction) \ DECLARE_CAST_BY_FLAG(UStaticMeshComponent) \ DECLARE_CAST_BY_FLAG(FEnumProperty) \ DECLARE_CAST_BY_FLAG(FNumericProperty) \ DECLARE_CAST_BY_FLAG(FInt8Property) \ DECLARE_CAST_BY_FLAG(FInt16Property) \ DECLARE_CAST_BY_FLAG(FInt64Property) \ DECLARE_CAST_BY_FLAG(FUInt16Property) \ DECLARE_CAST_BY_FLAG(FUInt32Property) \ DECLARE_CAST_BY_FLAG(FUInt64Property) \ DECLARE_CAST_BY_FLAG(FMapProperty) \ DECLARE_CAST_BY_FLAG(FSetProperty) \ DECLARE_CAST_BY_FLAG(USparseDelegateFunction) \ DECLARE_CAST_BY_FLAG(FMulticastInlineDelegateProperty) \ DECLARE_CAST_BY_FLAG(FMulticastSparseDelegateProperty) \ FINISH_DECLARING_CAST_FLAGS // This is here to hopefully remind people to include the "\" in all declarations above, especially when copy/pasting the final line. // Now actually declare the flags DECLARE_ALL_CAST_FLAGS #undef DECLARE_CAST_BY_FLAG #undef DECLARE_CAST_BY_FLAG_CAST #undef DECLARE_CAST_BY_FLAG_FWD #if HACK_HEADER_GENERATOR // Singleton class to get the cast flag for a given class name. struct COREUOBJECT_API ClassCastFlagMap { static ClassCastFlagMap& Get(); // Get Mapped name -> cast flag. Returns CASTCLASS_None if name is not found. EClassCastFlags GetCastFlag(const FString& ClassName) const; private: ClassCastFlagMap(); TMap CastFlagMap; }; #endif // HACK_HEADER_GENERATOR namespace UE4Casts_Private { template FORCEINLINE typename TEnableIf, TAnd::Type>, TIsCastable>>::Value, To>::Type DynamicCast(From* Arg) { typedef typename TRemovePointer::Type ToValueType; typedef typename TRemovePointer::Type FromValueType; // Casting away const/volatile static_assert(!TLosesQualifiersFromTo::Value, "Conversion loses qualifiers"); // If we're casting to void, cast to UObject instead and let it implicitly cast to void return Cast::Value, UObject, ToValueType>::Result>(Arg); } template FORCEINLINE typename TEnableIf, TAnd::Type>, TIsCastable>>::Value, To>::Type DynamicCast(From* Arg) { return dynamic_cast(Arg); } template FORCEINLINE typename TEnableIf::Type>, TIsCastable::Type>>::Value, To>::Type DynamicCast(From&& Arg) { typedef typename TRemoveReference::Type FromValueType; typedef typename TRemoveReference::Type ToValueType; // Casting away const/volatile static_assert(!TLosesQualifiersFromTo::Value, "Conversion loses qualifiers"); // T&& can only be cast to U&& // http://en.cppreference.com/w/cpp/language/dynamic_cast static_assert(TOr, TIsRValueReferenceType>::Value, "Cannot dynamic_cast from an rvalue to a non-rvalue reference"); return Forward(*CastChecked::Type>(&Arg)); } template FORCEINLINE typename TEnableIf::Type>, TIsCastable::Type>>::Value, To>::Type DynamicCast(From&& Arg) { // This may fail when dynamic_casting rvalue references due to patchy compiler support return dynamic_cast(Arg); } } // namespace UE4Casts_Private #define dynamic_cast UE4Casts_Private::DynamicCast