Download

For some reason, TIsPointer<> struct isn't confirming an explicit pointer type T. Why?

Hello guys, how are you doing?

I’m here one more time to ask for help.

You see, I have a class derived from AActor, where I’m coding a black hole skill, and a interface, where I have coded a sorting algorithm.

For some reason, in one of the subroutines of the sorting algorithm (ISortingAlgorithmsInterface::PartitionateArray), the compiler isn’t going through the if where a TIsPointer<> is verifying the generic type T present in the parameter list, and is going through the else, where a UObject member function is being accessed using . , not ->. In the code block where the sorting algorithm is being called (Tick method), a TArray<UPrimitive*> is passed as an argument. The type T is a pointer to some class, in this case, to a UPrimitiveComponent, and the else should deal only with non-pointer types.

Below, you can find the code:

INTERFACE



// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "SortingAlgorithmsInterface.generated.h"

// This class does not need to be modified.
UINTERFACE(MinimalAPI, Blueprintable, BlueprintType)
class USortingAlgorithmsInterface : public UInterface
{ GENERATED_BODY()
 
 
 };

/**
*
*/
class PRJ_PROJECTILETESTEX_API ISortingAlgorithmsInterface
{ GENERATED_BODY()

// Add interface functions to this class. This is the class that will be inherited to implement this interface.
protected:
template<typename T>
static uint8 PartitionateArray(TArray<T>& Arr, uint8 LowerBoundary, uint8 UpperBoundary);

template<typename T>
static uint8 PartitionateArrayRandomly(TArray<T>& Arr, uint8 LowerBoundary, uint8 UpperBoundary);

template<typename T>
static void Swap(T SwappableSubjectA, T SwappableSubjectB);
 
 
  public: template<typename T>
static void RandomizedQuickSort(TArray<T>& Arr, uint8 LowerBoundary, uint8 UpperBondaury);
 
 
 
};

template<typename T>
static uint8 ISortingAlgorithmsInterface::PartitionateArray(TArray<T>& Arr, uint8 LowerBoundary, uint8 UpperBoundary)
{ static_assert(TIsDerivedFrom<TRemovePointer<T>::Type, UObject>::IsDerived, "T is not derived from UObject class");
uint8 SortingIndex = LowerBoundary - 1;
//if (std::is_pointer<T>::value)
if(TIsPointer<T>::Value)
{
  [INDENT=2]uint8 Pivot = Cast<UObject>(Arr[UpperBoundary])->GetUniqueID();
for (int Index = LowerBoundary; Index <= UpperBoundary - 1; Index++)
{[/INDENT]
  [INDENT=3]if (Cast<UObject>(Arr[Index])->GetUniqueID() <= Pivot)
{
SortingIndex++;
Swap(Arr[SortingIndex], Arr[Index]);
}[/INDENT]
  [INDENT=2]}[/INDENT]
  }
  else
{
  [INDENT=2]uint8 Pivot = Cast<UObject>(Arr[UpperBoundary]).GetUniqueID();
for (int Index = LowerBoundary; Index <= UpperBoundary - 1; Index++)
{[/INDENT]
  [INDENT=3]if (Cast<UObject>(Arr[Index]).GetUniqueID() <= Pivot)
{
SortingIndex++;
Swap(Arr[SortingIndex], Arr[Index]);
}[/INDENT]
  [INDENT=2]}[/INDENT]
  }
Swap(Arr[SortingIndex + 1], Arr[UpperBoundary]);

return SortingIndex + 1;
 
 
 
}

template<typename T>
static uint8 ISortingAlgorithmsInterface::PartitionateArrayRandomly(TArray<T>& Arr, uint8 LowerBoundary, uint8 UpperBoundary)
{ //static_assert(std::is_base_of<UObject, T>::value, "T is not derived from UObject class");
static_assert(TIsDerivedFrom<TRemovePointer<T>::Type, UObject>::IsDerived, "T is not derived from UObject class");
uint8 RandomIndex = FMath::RandRange(LowerBoundary, UpperBoundary);
Swap(Arr[RandomIndex], Arr[UpperBoundary]);

return PartitionateArray(Arr, LowerBoundary, UpperBoundary);
 
 
 
}

template<typename T>
static void ISortingAlgorithmsInterface::RandomizedQuickSort(TArray<T>& Arr, uint8 LowerBoundary, uint8 UpperBoundary)
{ //static_assert(std::is_base_of<UObject, T>::value, "T is not derived from UObject class");
static_assert(TIsDerivedFrom<TRemovePointer<T>::Type, UObject>::IsDerived, "T is not derived from UObject class");
if (LowerBoundary < UpperBoundary)
{
  [INDENT=2]uint8 PartitionIndex = PartitionateArrayRandomly(Arr, LowerBoundary, UpperBoundary);
RandomizedQuickSort(Arr, LowerBoundary, PartitionIndex - 1);
RandomizedQuickSort(Arr, PartitionIndex + 1, UpperBoundary);[/INDENT]
  }
 
 
 
}

template<typename T>
static void ISortingAlgorithmsInterface::Swap(T SwappableSubjectA, T SwappableSubjectB)
{ //static_assert(std::is_base_of<UObject, T>::value, "T is not derived from UObject class");
static_assert(TIsDerivedFrom<TRemovePointer<T>::Type, UObject>::IsDerived, "T is not derived from UObject class");
T Temp = SwappableSubjectA;
SwappableSubjectA = SwappableSubjectB;
SwappableSubjectB = Temp;
 
 
 
}


SKILL



// Fill out your copyright notice in the Description page of Project Settings.


#include "BlackHoleSkill.h"
#include "Components/SphereComponent.h"
#include "Gameframework/ProjectileMovementComponent.h"
#include "GameFramework/Character.h"
#include "Engine/SkeletalMeshSocket.h"
#include "PRJ_ProjectileTestEXCharacter.h"
#include "NiagaraSystem.h"
#include "NiagaraComponent.h"
#include "NiagaraFunctionLibrary.h"
#include "DrawDebugHelpers.h"
#include "ProjectileTestEXConstants.h"
#include "Kismet/KismetMathLibrary.h"
#include "SortingAlgorithmsInterface.h"
#include "SearchingAlgorithmsInterface.h"

// Sets default values
ABlackHoleSkill::ABlackHoleSkill(const FObjectInitializer& ObjectInitializer)
{ // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;

BlackHoleGravitationalInfluenceSpace = ObjectInitializer.CreateDefaultSubobject<USphereComponent>(this, TEXT("BlackHoleGravitationalInfluenceSpace"));
BlackHoleGravitationalInfluenceSpace->SetSphereRadius(500);
BlackHoleGravitationalInfluenceSpace->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
FCollisionResponseContainer CollisionResponseContainer = FCollisionResponseContainer(ECollisionResponse::ECR_Ignore);
CollisionResponseContainer.SetResponse(ECollisionChannel::ECC_PhysicsBody, ECollisionResponse::ECR_Overlap);
BlackHoleGravitationalInfluenceSpace->SetCollisionResponseToChannels(CollisionResponseContainer);
BlackHoleGravitationalInfluenceSpace->SetGenerateOverlapEvents(true);
BlackHoleGravitationalInfluenceSpace->SetSimulatePhysics(false);
RootComponent = BlackHoleGravitationalInfluenceSpace;

/*BlackHoleEventHorizon = ObjectInitializer.CreateDefaultSubobject<UStaticMeshComponent>(this, TEXT("BlackHoleEventHorizon"));
BlackHoleEventHorizon->SetWorldScale3D(FVector(.25f, .25f, .25f));
BlackHoleEventHorizon->SetRelativeLocation(FVector(0.f, 0.f, 0.f));
BlackHoleEventHorizon->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
BlackHoleEventHorizon->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Overlap);
BlackHoleEventHorizon->SetGenerateOverlapEvents(true);
BlackHoleEventHorizon->SetSimulatePhysics(false);
BlackHoleEventHorizon->SetupAttachment(RootComponent);*/

BlackHoleVFXComp = ObjectInitializer.CreateDefaultSubobject<UNiagaraComponent>(this, TEXT("BlackHoleVFX"));
BlackHoleVFXComp->SetupAttachment(RootComponent);

BlackHoleMovementComp = ObjectInitializer.CreateDefaultSubobject<UProjectileMovementComponent>(this, TEXT("BlackHoleMovementComp"));
BlackHoleMovementComp->SetUpdatedComponent(BlackHoleGravitationalInfluenceSpace);
BlackHoleMovementComp->InitialSpeed = 0.f;
BlackHoleMovementComp->MaxSpeed = 0.f;
BlackHoleMovementComp->bRotationFollowsVelocity = true;
BlackHoleMovementComp->bShouldBounce = false;
BlackHoleMovementComp->ProjectileGravityScale = 0.f;
 
 
 
}

// Called when the game starts or when spawned
void ABlackHoleSkill::BeginPlay()
{ Super::BeginPlay();

SetLifeSpan(5.f);
UE_LOG(LogTemp, Warning, TEXT("Actor lifespan = %f"), InitialLifeSpan);
if (BlackHoleVFX)
{
  [INDENT=2]ACharacter* BlackHoleOwner = Cast<ACharacter>(GetOwner());
if (BlackHoleOwner)
{[/INDENT]
  [INDENT=3]BlackHoleVFXComp = UNiagaraFunctionLibrary::SpawnSystemAttached(
BlackHoleVFX,
RootComponent,
FName("BlackHoleVFX"),
BlackHoleOwner->GetMesh()->GetSocketLocation("hand_r"),
GetActorForwardVector().ToOrientationRotator(),
EAttachLocation::KeepWorldPosition,
false
);[/INDENT]
  [INDENT=2]}[/INDENT]
  }
 
 
 
}

bool ABlackHoleSkill::Compare(TArray<UPrimitiveComponent*> Arr1, TArray<UPrimitiveComponent*> Arr2)
{ bool IsEqual = false;
if(Arr1.Num() == Arr2.Num())
{
  [INDENT=2]IsEqual = true;
for(int Index = 0; Index <= Arr1.Num() - 1; Index++)
{[/INDENT]
  [INDENT=3]if(Arr1[Index]->GetUniqueID() != Arr2[Index]->GetUniqueID())
{[/INDENT]
  [INDENT=4]IsEqual = false;
return IsEqual;[/INDENT]
  [INDENT=3]}[/INDENT]
  [INDENT=2]}[/INDENT]
  }

return IsEqual;
 
 
 
}

FBlackHoleOrbitData ABlackHoleSkill::GenerateOrbitData(UPrimitiveComponent* OverlappedComponent)
{ FBlackHoleOrbitData NewOrbitData = FBlackHoleOrbitData();
NewOrbitData.OrbitID = OverlappedComponent->GetUniqueID();

return FBlackHoleOrbitData();
 
 
 }

void ABlackHoleSkill::EndPlay(const EEndPlayReason::Type EndPlayReason)
{ Super::EndPlay(EndPlayReason);

if (PreviouslyOverlapppedComponentArr.Num() > 0)
{
  [INDENT=2]for (UPrimitiveComponent* PreviouslyOverlappedComponent : PreviouslyOverlapppedComponentArr)
{[/INDENT]
  [INDENT=3]PreviouslyOverlappedComponent->SetEnableGravity(true);[/INDENT]
  [INDENT=2]}[/INDENT]
  }
 
 
 }

void ABlackHoleSkill::MoveInDirection(FVector Direction)
{ BlackHoleMovementComp->Velocity = Direction * BlackHoleMovementComp->InitialSpeed;
 
 
 }

void ABlackHoleSkill::PostInitializeComponents()
{ Super::PostInitializeComponents();

BlackHoleMass = BlackHoleMassScale * SUN_MASS;
 
 
 
}

// Called every frame
void ABlackHoleSkill::Tick(float DeltaTime)
{ Super::Tick(DeltaTime);

DrawDebugSphere(GetWorld(), GetActorLocation(), BlackHoleGravitationalInfluenceSpace->GetScaledSphereRadius(), 20, FColor::Red, false, .1f, 0, 2.f);

TArray<UPrimitiveComponent*> OverlappedComponentArr;
GetOverlappingComponents(OverlappedComponentArr);
TArray<UPrimitiveComponent*> TempArr;
for(UPrimitiveComponent* OverlappedComponent : OverlappedComponentArr)
{
  [INDENT=2]if(OverlappedComponent->GetOwner()->GetClass() != ACharacter::StaticClass())
{
TempArr.Add(OverlappedComponent);
}[/INDENT]
  }
ISortingAlgorithmsInterface::RandomizedQuickSort(TempArr, 0, TempArr.Num() - 1);
if(!Compare(TempArr, PreviouslyOverlapppedComponentArr) && TempArr.Num() > 0)
{
  [INDENT=2]for(int Index = 0; Index <= TempArr.Num() - 1; Index++)
{[/INDENT]
  [INDENT=3]if(OrbitDataArr.Num() == 0 || Index > OrbitDataArr.Num() - 1)
{

}
else
{[/INDENT]
  [INDENT=4]if(Index <= OrbitDataArr.Num() - 1 && (OrbitDataArr[Index].OrbitID != TempArr[Index]->GetUniqueID()))
{

}[/INDENT]
  [INDENT=3]}[/INDENT]
  [INDENT=2]}[/INDENT]
  }



if(PreviouslyOverlapppedComponentArr.Num() > 0)
{
  [INDENT=2]for(UPrimitiveComponent* PreviouslyOverlappedComponent : PreviouslyOverlapppedComponentArr)
{[/INDENT]
  [INDENT=3]if(!OverlappedComponentArr.Contains(PreviouslyOverlappedComponent))
{[/INDENT]
  [INDENT=4]PreviouslyOverlappedComponent->SetEnableGravity(true);[/INDENT]
  [INDENT=3]}[/INDENT]
  [INDENT=2]}[/INDENT]
  }
PreviouslyOverlapppedComponentArr = OverlappedComponentArr;
 
 
 
}



OUTPUT LOG



1>------ Build started: Project: PRJ_ProjectileTestEX, Configuration: Development_Editor x64 ------
2>------ Skipped Build: Project: UE4, Configuration: BuiltWithUnrealBuildTool Win32 ------
2>Project not selected to build for this solution configuration
1>Building PRJ_ProjectileTestEXEditor...
1>Using Visual Studio 2019 14.22.27905 toolchain (D:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.22.27905) and Windows 10.0.18362.0 SDK (C:\Program Files (x86)\Windows Kits\10).
1>Building 4 actions with 12 processes...
1> [1/4] BlackHoleSkill.cpp
1>D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Source\PRJ_ProjectileTestEX\SortingAlgorithmsInterface.h(60): error C2228: left of '.GetUniqueID' must have class/struct/union
1> D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Source\PRJ_ProjectileTestEX\SortingAlgorithmsInterface.h(60): note: type is 'To *'
1> with
1> 
1> To=UObject
1> ]
1> D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Source\PRJ_ProjectileTestEX\SortingAlgorithmsInterface.h(60): note: did you intend to use '->' instead?
1> D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Source\PRJ_ProjectileTestEX\SortingAlgorithmsInterface.h(84): note: see reference to function template instantiation 'uint8 ISortingAlgorithmsInterface::PartitionateArray<UPrimitiveComponent*>(TArray<UPrimitiveComponent *,FDefaultAllocator> &,uint8,uint8)' being compiled
1> D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Source\PRJ_ProjectileTestEX\SortingAlgorithmsInterface.h(95): note: see reference to function template instantiation 'uint8 ISortingAlgorithmsInterface::PartitionateArrayRandomly<UPrimitiveComponent*>(TArray<UPrimitiveComponent *,FDefaultAllocator> &,uint8,uint8)' being compiled
1> D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Source\PRJ_ProjectileTestEX\BlackHoleSkill.cpp(266): note: see reference to function template instantiation 'void ISortingAlgorithmsInterface::RandomizedQuickSort<UPrimitiveComponent*>(TArray<UPrimitiveComponent *,FDefaultAllocator> &,uint8,uint8)' being compiled
1>D:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Microsoft\VC\v160\Microsoft.MakeFile.Targets(44,5): error MSB3073: The command ""D:\Program Files\Epic Games\UE_4.25\Engine\Build\BatchFiles\Build.bat" PRJ_ProjectileTestEXEditor Win64 Development -Project="D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\PRJ_ProjectileTestEX.uproject" -WaitMutex -FromMsBuild" exited with code 6.
1>Done building project "PRJ_ProjectileTestEX.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 1 skipped ==========



What am I doing wrong? Doesn’t TIsPointer<> work properly?

Thanks! :smiley:

You can’t do what you’re trying to do. What’s happening here is that you have code meant for pointer and non-pointer types in the same function. If you try to compile a version for a pointer type, it will give you a compile error in the else scope and vice versa.

Assuming that:

  • UObject is non-copyable
  • TArray can’t hold references
  • Your function requires the T to inherit from UObject

The only possibility is to pass an array of pointers to UObject-derivatives. So you don’t need a path for a non-pointer types.

As said above, TArray<UObject> can’t exist, so you don’t need the other path. But if it did, the way to make it work would be either more template specializations or if constexpr.

Thanks for the replies and sorry for make you wait for a feedback, guys!

I read about the if constexpr, here c++ - Difference between "if constexpr()" Vs "if()" - Stack Overflow and here Coding Games and Programming Challenges to Code Better

I’ll change the code right now! =D