Unexpected Unreal Behaviour
Introduction
This is notes on Unreal Engine behaviour which might surprise.
- The Unreal Header Tool sometimes changes method parameter declarations
- The Unreal Header Tool is not fully satisfied by forward declarations
The Unreal Header Tool sometimes changes method parameter declarations
Given a class declared like this:
USTRUCT(BlueprintType)
struct EXAMPLE_API FActionContainer
{
GENERATED_BODY()
};
UCLASS()
class EXAMPLE_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AMyCharacter();
UFUNCTION(BlueprintImplementableEvent, Category = "Interaction")
void OpenExpandableItemActions(TArray<FActionContainer> actions);
};
The above code will not compile. In the output window we get this error:
1>MyCharacter.gen.cpp(71): error C2511:
'void AMyCharacter::OpenExpandableItemActions(const TArray<FActionContainer,FDefaultAllocator> &)':
overloaded member function not found in 'AMyCharacter'
1>MyCharacter.h(19):
note: see declaration of 'AMyCharacter'
1>MyCharacter.gen.cpp(75):
error C2352: 'UObject::FindFunctionChecked': a call of a non-static member function requires an object
1>Object.h:
see declaration of 'UObject::FindFunctionChecked'
What is happening here is that the Unreal Header Tool (UHT) is generating code into the file MyCharacter.gen.cpp, and the code it is generating has different parameter types than the code in our class declaration. The code in the generated .cpp file looks like this:
static FName NAME_AMyCharacter_OpenExpandableItemActions = FName(TEXT("OpenExpandableItemActions"));
void AMyCharacter::OpenExpandableItemActions(const TArray<FActionContainer>& actions)
{
MyCharacter_eventOpenExpandableItemActions_Parms Parms;
Parms.actions=actions;
ProcessEvent(FindFunctionChecked(NAME_AMyCharacter_OpenExpandableItemActions),&Parms);
}
This code is generated to support the BlueprintImplementableEvent
aspect of the
OpenExpandableItemActions
method, so that the method can be implemented
in a blueprint rather than in c++.
The UHT generates code which uses the types which blueprint supports, which in this
example are different from the types we used when declaring OpenExpandableItemActions
.
Specifically UHT changes the type of the actions
parameter
from TArray<FActionContainer>
to const TArray<FActionContainer>&
, i.e.
it changes a value type to a const reference type.
The solution to this error is to change our header to define the method the way UHT wants, i.e. using a const reference like this:
UCLASS()
class GARBAGECOLLECTION_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
// Sets default values for this character's properties
AMyCharacter();
UFUNCTION(BlueprintImplementableEvent, Category = "Interaction")
void OpenExpandableItemActions(const TArray<FActionContainer>& actions);
};
The Unreal Header Tool is not fully satisfied by forward declarations
If you generate a first person game project with C++ from the Unreal Editor you create a file
called Character.h. This contains forward declares the type USkeletalMeshComponent
and then uses it like this:
...
class USkeletalMeshComponent;
...
UCLASS(config=Game)
class AProjectCharacter : public ACharacter
{
GENERATED_BODY()
/** Pawn mesh: 1st person view (arms; seen only by self) */
UPROPERTY(VisibleDefaultsOnly, Category=Mesh)
USkeletalMeshComponent* Mesh1P;
...
}
This makes it look as though when UHT processes the UPROPERTY
macro it uses the forward
declaration to resolve the USkeletalMeshComponent
type. But it does not. If you
change the USkeletalMeshComponent
type to something which does not exist such as NonExistantClass
like so:
...
class NonExistantClass;
...
UCLASS(config=Game)
class AProjectCharacter : public ACharacter
{
GENERATED_BODY()
/** Pawn mesh: 1st person view (arms; seen only by self) */
UPROPERTY(VisibleDefaultsOnly, Category=Mesh)
NonExistantClass* Mesh1P;
...
}
This will not compile, it fails with this error:
1>ProjectCharacter.h(28): error : Unrecognized type 'NonExistantClass' - type must be a UCLASS, USTRUCT,
UENUM, or global delegate.
Using a forward declaration to a non-existant class would work in straight C++, but the UHT must be parsing the engine and project code and maintaining a list of UCLASS, USTRUCT, UENUM types and failing if it does not find the specified type.
Feedback
Please leave any feedback about this article here