Forward declarations and TSubclassOf: what poisoned my project?

I’m stumped by a UE4 mystery, and hoping for help. It seems my project has lost the capacity to handle forward declarations in conjunction with TSubclassOf variable declarations.

What I wanted was simple. I had a project with a UObject-derived class in which I wanted to create a variable which I could, through blueprints, set equal to a particular blueprint class. To avoid circular dependencies, I don’t want to #include the class of the object in question. Forward declarations are the answer! But they don’t work.

After a lot of frustration, I created a new project (TestProj) and tried something out. I created two new classes: Porkchop and HamSalad, both subclasses of Object. Here is Porkchop.h:

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

#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "Porkchop.generated.h"

/**
 * 
 */


UCLASS()
class TESTPROJ_API UPorkchop : public UObject
{
	GENERATED_BODY()
	
	
public:

	
	
};

And here is HamSalad.h:

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

#pragma once

#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "HamSalad.generated.h"

/**
 * 
 */
UCLASS()
class TESTPROJ_API UHamSalad : public UObject
{
	GENERATED_BODY()
	
	TSubclassOf<class UPorkchop> MainCourse;
};

Visual Studio 2017 is not happy with this; MainCourse has the squiggly red underline, with the tooltip “Incomplete type is not allowed”. Nevertheless, it compiles.

Now here’s the part that has me pulling my hair out: if I add these two classes, Porkchop and HamSalad, both derived from UObject and exactly as described above, to MY project, it does not compile. I get this in Visual Studio’s output:

F:\UE4\Oafmatch\Source\Oafmatch/HamSalad.h(17): error C2079: 'UHamSalad::MainCourse' uses undefined class 'TSubclassOf<UPorkchop>'

More weirdness: if I add the line

TSubclassOf<class UPorkchop> MainCourse;

to the body of any AActor-derived class in my project, it compiles. But not in any UObject-derived class.

What on earth is going on here?

Doing so instead of including the ‘class’ keyword in TSubclassOf<class UPorkchop> MainCourse; has no effect, unfortunately. It compiles on a fresh project, but not on my existing project. And the existing project is like two weeks old.

I’m not sure, but shouldn’t you declare the UPorkchop class name somewhere before UCLASS() to use this type?

class UPorkchop;

More information:

As one would expect, without a proper #include or forward declaration, the line

UPorkchop* MainCourse;

causes errors. This one is fine:

class UPorkchop* MainCourse;

So that’s all working as expected. There’s something about the use of ‘TSubclassOf’ that’s causing problems.

Still more information:

A partial solution, though an unsatisfying one. Adding this made it work:

#include "Runtime/CoreUObject/Public/Templates/SubclassOf.h"

Why would I suddenly need to start doing that to make use of ‘TSubclassOf’? What changed? This engine drives me insane at times.

Have you tried deleting your intermediate, .vs, saved, and .sln files and then regerenating them and building again? When weird things like this happen to me, that usually fixes it. If that doesn’t help then unfortunately I’m at a loss for what the problem could be.

Yes, I forgot to mention that. I’ve deleted intermediate, .vs, saved, binaries, and .sln file and rebuilt. That’s fixed several other weird issues for me, but not this one. Thanks for the reply!

Same crazy issue here. I was seeing it when changing build configs in Visual Studio, but it would only happen during the first build attempt. Subsequent attempts were successful :/.

You do see it every time when building from UnrealBuildTool, though, which is where I was stuck.

Your partial solution of including the SubclassOf.h file saved me… thanks! I guess I’ll just chock this one up to another great mystery of UE4 C++ dev :).

I ran into the same issue today and these are my findings.

Short version:

As @Merrick advised, you are missing include Runtime/CoreUObject/Public/Templates/SubclassOf.h

Longer version, for JTJones853:

Not sure if you are aware, but Unreal uses a system called Unity builds (nothing to do with the other game engine…) which combines multiple C++ files into bigger blobs to reduce compile times. While great, they easily hide missing header includes. You may forget to add a needed #include but not notice that, since it’s found in the Unity blob and thus compiles fine. Then later down the line, the Unity build system decides to build those blobs just a bit differently, and then the blob does not have that needed header in it. That can cause those weird “but it worked before!” or “but it works now!” errors.

So, in this case I assume that the project where your code worked, some OTHER file in the project includes either directly or non-directly the SubclassOf.h and since it happens to be in the Unity build blob, it works. Then in your project the blob doesn’t have it, and it fails. The error message actually gives a clue by complaining about ‘TSubclassOf’ instead of just UPorkchop, which is something I just realized myself :slight_smile:

So the error is correct. It doesn’t know what TSubclassOf means, and is fixed by including the header where it is defined.

Also when the code works, you might be including some larger header which indirectly includes the SubclassOf.h up its include hierarchy. I’d imagine that Actor.h does that and that’s why the code works when you use AActor as your base class, but not when you use UObject.

To combat these issues at work, when developing we have Adaptive Unity Builds enabled which tries to exclude the files being worked on from those Unity blobs, so that you’d catch the missing header includes early. Note that I think currently it requires you to use either Git or Plastic version controlling to get the list of files being worked on. (We have also added support for Plastic which we use at work).

A sure way is to turn off Unity builds completely, which may also increase your compile times IF you’re always iterating over a small set of C++ files. Though large re-compiles will get slower. At work as mentioned we work with Adaptive Unity builds turned on, but in addition we constantly run automated builds with Unity builds turned OFF to catch any header include issues. (That includes automated Slack messages to relevant programmers to fix their stuff :D)

Hope this helped someone.

Relevant info:

4 Likes

Actually just had a look and Actor.h has
#include “Templates/SubclassOf.h”

So that’s why it works with Actors :slight_smile:

1 Like