UENUM causing circular dependency

Hi, i have the following code:
LibertyCharacter.h:

UFUNCTION()
virtual void OnDeathStateChanged(ULibertyHealthComponent* HealthComponent, ELibertyDeathState OldDeathState, ELibertyDeathState NewDeathState);

These are my forward declares in my LibertyCharacter.h file:

class ULibertyHealthComponent;
enum class ELibertyDeathState : uint8;

ULibertyHealthComponent has LibertyCharacter.h included in it as i was unable to forward declare USTRUCT from LibertyCharacter.h.

Now with this UFunction: OnDeathStateChanged, when i compile i get these errors:

C:\Users\Fractal\Documents\Unreal Projects\Liberty\Source\Liberty\LibertyCharacter.h(1): Error: Circular dependency detected:
C:\Users\Fractal\Documents\Unreal Projects\Liberty\Source\Liberty\LibertyCharacter.h(1): Error: includes/requires ‘C:\Users\Fractal\Documents\Unreal Projects\Liberty\Source\Liberty\LibertyHealthComponent.h’
C:\Users\Fractal\Documents\Unreal Projects\Liberty\Source\Liberty\LibertyHealthComponent.h(1): Error: includes/requires ‘C:\Users\Fractal\Documents\Unreal Projects\Liberty\Source\Liberty\LibertyCharacter.h’

But, when i remove UFUNCTION tag from OnDeathStateChanged, it compiles.
Am i missing something really obvious?

In LibertyCharacter.h forward declare ULibertyHealthComponent and add and include to LibertyHealthComponent.h in LibertyCharacter.cpp

Basically forward declare anything you can in the header definitions and then include the needed headers in the cpp files.

I would also suggest extracting enums out of the main files unless they are only used there once.

LibertyHealthComponent.h should not include LibertyCharacter.h in it’s header.

Forward declarations circumvent circular dependencies.

1 Like

The reason i had to include LibertyCharacter.h in LibertyHealthComponent.h is because of unable to forward declare USTRUCT: FLibertyGeneralMovementSettings which is present in LibertyCharacter.h.

LibertyCharacter.h:

// Forward declares
class ULibertyHealthComponent;
enum class ELibertyDeathState : uint8;

USTRUCT(BlueprintType)
struct FLibertyGeneralMovementSettings
{
	GENERATED_BODY()
};

LibertyCharacter.cpp:

#include "LibertyCharacter.h"
#include "LibertyHealthComponent.h"

LibertyHealthComponent.h

#include "LibertyCharacter.h"

// Tried to do this earler (instead of including LibertyCharacter.h and then including in .cpp) but didnt work. This was the initial problem.
struct FLibertyGeneralMovementSettings;

Seeing that FLibertyGeneralMovementSettings is used in more than one place should push you to atomize it by extracting it to it’s on file (maybe a common struct file or a movement file). Strip out the dependency then you can forward declare in both files.

Yea i will try that, thanks.

I have a question, can you not use UEnum in UFunction if the UEnum was forward declared?

enum class ELibertyDeathState : uint8;

UFUNCTION()
virtual void OnDeathStateChanged(ULibertyHealthComponent* HealthComponent, ELibertyDeathState OldDeathState, ELibertyDeathState NewDeathState);

If i comment UFUNCTION, the code will compile and not throw any circular dependency!?

You can but it depends where you forward declared it.

If you want the forward declaration to span the whole file then put it above the UClass of the main file you are in. If you just forward declare inside of the class properties then you have to keep forward declaring even inside of UFunctions over and over again.

So it’s best to declare it up top similarly like with delegates.

so you could also do:

virtual void OnDeathStateChanged(class ULibertyHealthComponent* HealthComponent, enum ELibertyDeathState OldDeathState, enum ELibertyDeathState NewDeathState);

or just once up top of the file bellow the includes once:

enum ELibertyDeathState;
class ULibertyHealthComponent;

But why doesn’t (OnDeathStateChanged) it compile with the UFUNCTION() tag?

I want it to be a UFunction since its bind to a delegate.

Are the forward declarations up top just below you .generated.h include?

Yes:


#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Logging/LogMacros.h"
#include "Misc/DateTime.h"
#include "HAL/PlatformTime.h"

#include "LibertyCharacter.generated.h"

class USpringArmComponent;
class UCapsuleComponent;
class UCameraComponent;
class UArrowComponent;
class UInputMappingContext;
class UInputAction;
class ULibertyMovementComponent;

enum class ELibertyDeathState : uint8;
class ULibertyHealthComponent;

struct FInputActionValue;

UCLASS(config=Game)
class ALibertyCharacter : public ACharacter
{
	GENERATED_BODY()

public:
//UFUNCTION()
virtual void OnDeathStateChanged(ULibertyHealthComponent* HealthComponent, ELibertyDeathState OldDeathState, ELibertyDeathState NewDeathState);

};

reduce the enum forward declaration to:

enum class ELibertyDeathState;

It may not be picking up the correct forward declaration (you do not state what it is derived from)

The compiler assumes it is an int, and throws errors.

I think this might be UENUM and UFUNCTION limitation of some sort? Probably to do with UENUM size, the compiler don’t know its size when passing as a parameter to a UFUNCTION?
Because without UFUNCTION() over OnDeathStateChanged, no problems!

idk i am just scratching my head at this point!

it works you just have to add the UENUM() macro to the enum to forward declare it in ufunctions

Working simple version of the project with forward declarations and enum isolation:
EnumFDec.zip (8.5 KB)

You can regenerate it and it compiles zero errors

compile output

Mockup enum

obraz

Forward declare

obraz

Then include of the enum file

obraz

And if i make it blueprint callable here it is in the editor :slight_smile:
obraz

obraz

I see, you are using a seperate file for enums, thats the only difference i see in your code and mine, and this might just be the only solution (atleast for now).

I am not going to dig around more about this, i have been doing that for a minute! I appreciate you man, thanks for your precious time.

1 Like

Glad I could be of help.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.