Help With C++ Sort By Predicate

Actually, using a struct with state is identical to using a lambda with a capture. A lambda is not like a function pointer, though capture-less lambdas are convertible to function pointers.

The FSortByDistance code above is equivalent to the following with a lambda:

FVector SourceLocation = ControlledMob->GetActorLocation();
GetSensedActors().Sort([SourceLocation](const AActor& A, const AActor& B)
{
    float DistanceA = FVector::DistSquared(SourceLocation, A.GetActorLocation());
    float DistanceB = FVector::DistSquared(SourceLocation, B.GetActorLocation());

    return DistanceA > DistanceB;
});

But while lambdas are more than capable of expressing stateful predicates, you may still want to define a standalone FSortByDistance struct to allow code reuse.

However, note that I have changed the code above to pass AActor by reference instead of by pointer. This is due to a legacy decision that causes TArray::Sort() to auto-deference pointers, and will have been the reason for your compile errors. Unfortunately, we can’t realistically revert that behaviour now, so instead, you should prefer to use Algo::Sort over TArray::Sort, as this correctly passes pointers to the predicate as expected:

struct FSortByDistance
{
    explicit FSortByDistance(const FVector& InSourceLocation)
        : SourceLocation(InSourceLocation)
    {
    }

    /* The Location to use in our Sort comparison. */
    FVector SourceLocation;

    bool operator()(const AActor* A, const AActor* B) const
    {
        float DistanceA = FVector::DistSquared(SourceLocation, A->GetActorLocation());
        float DistanceB = FVector::DistSquared(SourceLocation, B->GetActorLocation());

        return DistanceA > DistanceB;
    }
};

Algo::Sort(GetSensedActors(), FSortByDistance(ControlledMob->GetActorLocation()));

Hope this helps,

Steve

2 Likes