Unresolved external symbol, but the code implementation is inside the .cpp

Hi guys!

I’m coding a skill mechanic and, for some reason, I’m getting, at the output log, an unresolved external symbol. I was looking for any kind of error I possibly have done, but I couldn’t find it. The implementation is inside the Interface .cpp.



// 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);
 
};




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


#include "SortingAlgorithmsInterface.h"

// Add default functionality here for any ISortingAlgorithmsInterface functions that are not pure virtual.
template<typename T>
static uint8 ISortingAlgorithmsInterface::PartitionateArray(TArray<T>& Arr, uint8 LowerBoundary, uint8 UpperBoundary)
{ static_assert(is_base_of<UObject, T>::value, "T is not derived from UObject class");
uint8 SortingIndex = LowerBoundary - 1;
if(is_pointer<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)
{[/INDENT]
  [INDENT=4]SortingIndex++;
Swap(Arr[SortingIndex], Arr[Index]);[/INDENT]
  [INDENT=3]}[/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)
{[/INDENT]
  [INDENT=4]SortingIndex++;
Swap(Arr[SortingIndex], Arr[Index]);[/INDENT]
  [INDENT=3]}[/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(is_base_of<UObject, T>::value, "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(is_base_of<UObject, T>::value, "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(is_base_of<UObject, T>::value, "T is not derived from UObject class");
T Temp = SwappableSubjectA;
SwappableSubjectA = SwappableSubjectB;
SwappableSubjectB = Temp;
 
}




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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "BlackHoleSkill.generated.h"

class UNiagaraSystem;
class UNiagaraComponent;
class UProjectileMovementComponent;
class USphereComponent;

USTRUCT(BlueprintType)
struct FBlackHoleOrbitData
{ GENERATED_BODY()

UPROPERTY()
float MajorOrbitRadius;

UPROPERTY()
float OrbitAngle;

UPROPERTY()
bool OrbitFlag = false;

UPROPERTY()
uint32 OrbitID;
  public:
  
FBlackHoleOrbitData(){}
 
};

UCLASS()
class PRJ_PROJECTILETESTEX_API ABlackHoleSkill : public AActor
{ GENERATED_BODY()

UPROPERTY(EditDefaultsOnly, Category = "Properties", meta = (AllowPrivateAccess = "true"))
UStaticMeshComponent* BlackHoleEventHorizon;

UPROPERTY(VisibleDefaultsOnly, Category = "Properties", meta = (AllowPrivateAccess = "true"))
USphereComponent* BlackHoleGravitationalInfluenceSpace;

UPROPERTY(EditDefaultsOnly, Category = "Properties", meta = (AllowPrivateAccess = "true"))
float BlackHolePullForce;

UPROPERTY()
float BlackHoleMass;

UPROPERTY(EditDefaultsOnly, Category = "Properties", meta = (AllowPrivateAccess = "true"))
float BlackHoleMassScale;

UPROPERTY(EditDefaultsOnly, Category = "Visual Effects", meta = (AllowPrivateAccess = "true"))
UNiagaraSystem* BlackHoleVFX;

UPROPERTY()
UNiagaraComponent* BlackHoleVFXComp;

UPROPERTY()
UProjectileMovementComponent* BlackHoleMovementComp;

bool Compare(TArray<UPrimitiveComponent*> Arr1, TArray<UPrimitiveComponent*> Arr2);

UPROPERTY(EditDefaultsOnly, Category = "Properties", meta = (AllowPrivateAccess = "true"))
float EllipticalMovementRate;

FBlackHoleOrbitData GenerateOrbitData(UPrimitiveComponent* OverlappedComponent);

UPROPERTY(EditDefaultsOnly, Category = "Properties", meta = (AllowPrivateAccess = "true"))
float MajorEllipticOrbitFraction;

UPROPERTY()
TArray<FBlackHoleOrbitData> OrbitDataArr;

UPROPERTY()
TArray<UPrimitiveComponent*> PreviouslyOverlapppedComponentArr;
 
public: // Sets default values for this actor's properties
ABlackHoleSkill(const FObjectInitializer& ObjectInitializer);
 
protected: // Called when the game starts or when spawned
virtual void BeginPlay() override;

virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
  public:
  void MoveInDirection(FVector Direction);

virtual void PostInitializeComponents() override;

// Called every frame
virtual void Tick(float DeltaTime) override;
 
};




// 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())
{[/INDENT]
  [INDENT=3]TempArr.Add(OverlappedComponent);[/INDENT]
  [INDENT=2]}[/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;
 
}





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 2 actions with 12 processes...
1> [1/2] UE4Editor-PRJ_ProjectileTestEX.dll
1> Creating library D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Intermediate\Build\Win64\UE4Editor\Development\PRJ_ProjectileTestEX\UE4Editor-PRJ_ProjectileTestEX.suppressed.lib and object D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Intermediate\Build\Win64\UE4Editor\Development\PRJ_ProjectileTestEX\UE4Editor-PRJ_ProjectileTestEX.suppressed.exp
1>BlackHoleSkill.cpp.obj : error LNK2019: unresolved external symbol "public: static void __cdecl ISortingAlgorithmsInterface::RandomizedQuickSort<class UPrimitiveComponent *>(class TArray<class UPrimitiveComponent *,class TSizedDefaultAllocator<32> > &,unsigned char,unsigned char)" (??$RandomizedQuickSort@PEAVUPrimitiveComponent@@@ISortingAlgorithmsInterface@@SAXAEAV?$TArray@PEAVUPrimitiveComponent@@anonymous_user_e71e0d8a?$TSizedDefaultAllocator@$0CA@@@@@EE@Z) referenced in function "public: virtual void __cdecl ABlackHoleSkill::Tick(float)" (?Tick@ABlackHoleSkill@@UEAAXM@Z)
1>D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Binaries\Win64\UE4Editor-PRJ_ProjectileTestEX.dll : fatal error LNK1120: 1 unresolved externals
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 ==========



Can you help me to find this issue?

Thanks!

What I would suggest:

1 - Don’t use Interface. **Interface **is like: “I **do **it” for classes that inherit it. But in your code no class is inheriting your interface.
2 - Use UObject instead, for example, for your helper methods.
3 - Keep your **template<> **implementation in the same file your are declaring them ( .h ).

Thanks for your reply, SolidSk! :slight_smile:

I have chosen an Interface because you can find some acting as helpers (even though they act as a contract established with a class), doing an default implementation and leaving a breach to the classes that want to extend the code (not my case, because the methods are static). But I agree with you, using an UObject would be a more elegant solution.

I’ll paste the implementation in the .h and see what happens.

Thanks! :slight_smile:

EDIT: I was using is_base_of<Base, Derived> to verify an indirect inheritance (UObject and UPrimitiveComponent), but apparently the struct deals with direct inheritance only (std::is_base_of - cppreference.com). That’s why I wrote that template, to allow the processing of any kind of object that derived from UObject.

Is there a way to verify this indirect inheritance? Or should I start to use a sequence of nested verifications to achieve it?

Thanks!

You could use **IsA() **:
https://docs.unrealengine.com/en-US/…A/2/index.html
https://answers.unrealengine.com/questions/49076/how-to-use-isa-to-check-is-an-actor-is-of-a-class.html

Yeah, what SolidSk said. You should try to always use the UE4 specific casting and class hierarchy code. It will be much more performant.

Thanks for your reply :slight_smile:

Yes, I did see the IsA() in the reference, but IsA() should be called from AActor instance. On my case, I can’t use it with a template =<

IsA and all the rest of UE4’s RTTI is available in anything that inherits from UObject.

Use TIsDerivedFrom:
https://docs.unrealengine.com/en-US/…rom/index.html

Example in Unreal’s code:



static_assert(TIsDerivedFrom<T, UARTrackedGeometry>::IsDerived, "T must be derived from UARTrackedGeometry");


Ah, I misunderstood what you were saying. Yeah, again, listen to SolidSk. I’ll just be going now. :stuck_out_tongue:

@SolidSk, @ ddbrown30,

Thanks for your patience and support :slight_smile:

I’ll the TIsDerivedFrom struct to see if I solve it

EDIT: Unfortunately, TIsDerivedFrom acts exactly as is_base_of, that only verifies a direct inheritance. When I write static_assert(TIsDerivedFrom<T, UObject>::IsDerived, “T is not derived from UObject class”), I get this




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>Creating makefile for PRJ_ProjectileTestEXEditor (no existing makefile)
1>Parsing headers for PRJ_ProjectileTestEXEditor
1> Running UnrealHeaderTool "D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\PRJ_ProjectileTestEX.uproject" "D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Intermediate\Build\Win64\PRJ_ProjectileTestEXEditor\Development\PRJ_ProjectileTestEXEditor.uhtmanifest" -LogCmds="loginit warning, logexit warning, logdatabase error" -Unattended -WarningsAsErrors -abslog="C:\Users\ShanxTadeu\AppData\Local\UnrealBuildTool\Log_UHT.txt" -installed
1>Reflection code generated for PRJ_ProjectileTestEXEditor in 10,1283873 seconds
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 17 actions with 12 processes...
1> [1/17] Default.rc2
1> [2/17] SharedPCH.Engine.ShadowErrors.cpp
1> [3/17] PRJ_ProjectileTestEX.cpp
1> [4/17] SearchingAlgorithmsInterface.cpp
1> [5/17] SortingAlgorithmsInterface.cpp
1> [6/17] PRJ_ProjectileTestEX.init.gen.cpp
1> [7/17] SearchingAlgorithmsInterface.gen.cpp
1> [8/17] SortingAlgorithmsInterface.gen.cpp
1> [9/17] PRJ_ProjectileTestEXGameMode.cpp
1> [10/17] PRJ_ProjectileTestEXGameMode.gen.cpp
1> [11/17] PRJ_ProjectileTestEXCharacter.gen.cpp
1> [12/17] BlackHoleSkill.gen.cpp
1> [13/17] PRJ_ProjectileTestEXCharacter.cpp
1> [14/17] BlackHoleSkill.cpp
1>D:\GAME DEVELOPMENT\PROJECTS\UDEMY\LATEST\PRJ_ProjectileTestEX\Source\PRJ_ProjectileTestEX\SortingAlgorithmsInterface.h(92): error C2338: T is not derived from UObject class
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 ==========


TIsDerivedFrom works fine.
Note that you are passing an array of pointers, not an array of objects. For this reason your T in template is deduced as UPrimitiveComponent*, not UPrimitiveComponent.

You need to remove pointer from the type before check:



template<typename T>
static void ISortingAlgorithmsInterface::RandomizedQuickSort(TArray<T>& Arr, uint8 LowerBoundary, uint8 UpperBoundary)
{
  static_assert(TIsDerivedFrom<TRemovePointer<T>::Type, UObject>::Value, "T is not derived from UObject class");
  // ... 
}


Thanks for your reply! I’ve changed that =D