The dreaded read squiggles after changes to Unreal header files are caused by Visual Studio not understanding the Unreal build system, and they shouldn’t really influence your choice of where to put your includes. I’ll get back to that at the end of the post.
The usual guideline is to include as few other headers as possible in header files. This reduces dependencies between headers and can greatly reduce compile times in large systems. Of course each header should still include what it needs, you don’t want a header that only works if somebody else includes its dependencies.
UOpenDoor inherits from
UActorComponent you need the complete definition of that class and thus have to include the
UOpenDoor only stores a pointer to
ATriggerVolume, so the header needs no information about the size of
ATriggerVolume instances in memory or the methods that can be called on them. Therefore, in a larger project I would forward declare
ATriggerVolume in the header file and include
Engine/TriggerVolume.h in the corresponding
.cpp file. So my
OpenDoor.h file would start like this:
Having said that, in small projects like the ones in this course it’s not really necessary to worry about compilation speed or dependencies, so you can just include the
Engine/TriggerVolume.h header in
OpenDoor.h and be done with it.
Back to the red squiggles that we all know and love.
To understand why they appear even when you make only minimal changes, such as inserting a blank line, it helps to look at the Unreal build process.
In order to provide all the wonderful reflection features that are not present in standard C++, Unreal performs a preprocessing step before feeding your code to the C++ compiler. The program that does this is called the Unreal Header Tool (UHT), and it is responsible for generating the code that integrates your classes with the reflection code written by Epic’s wizards. This generated code lives in the
.generated.h file that you have to include after all other includes.
The function of macros such as
GENERATED_BODY() is essentially to insert a “hook” into your files where the code generated by UHT can attach to your code. But that is a bit of a problem, since the generated code is different for each class (or struct, etc.) that you define. Since it’s common to define multiple classes that need a
GENERATED_BODY() macro inside a single file UHT can’t just write a definition of
GENERATED_BODY into the
.generated.h file since then the same code would be added to all classes in the file. To solve this problem, many Unreal macros expand into other macros that include the line number on which the macro appeared. For example, in my
OpenDoor.h header file the
GENERATED_BODY() macro appears in line 15, so you can imagine that it is replaced by
GENERATED_BODY_15(). If I had another occurence of
GENERATED_BODY() in line 79, that occurence would be replaced by
GENERATED_BODY_79(), and so on.
It is important to note that this expansion is done by Visual Studio using standard C++ language features, so Visual Studio is actually responsible for producing the
GENERATED_BODY_15() macro call inside
OpenDoor.h. UHT knows about this scheme, of course, and inserts the definition of
GENERATED_BODY_15 into the
.generated.h file. So everything works out nicely.
But what happens when we insert a blank line at the start of the file?
GENERATED_BODY() appears no longer in line 15 but in line 16. Visual Studio, rightly, thinks that it should therefore expand the macro to
GENERATED_BODY_16(). But the
.generated.h file is only regenerated when UHT runs, so it still contains the definition of
GENERATED_BODY_15(), not the one we now need. Visual Studio therefore no longer knows about all the goodies that Unreal defines for us, and your carefully crafted code turns into a mess of red squiggles and warnings.
I hope that the solution has by now become pretty obvious: Just recompile the header; the Unreal Build Tool will figure out that something has changed, call UHT to re-generate the
.generated.h file and life will be good again.
Except that, well, sometimes this doesn’t help.
The reason for that seems to be that the generated headers live in the
Intermediate folder, and depending on your version of UE4 and Visual Studio, sometimes VS doesn’t seem to realize that new versions of files in
Intermediate have become available. In that case, right clicking inside the source of the offending header in VS and selecting
Rescan -> Rescan File solves the problem quite reliably with recent versions of VS and UE4.
Edit: It might be that even re-scanning the file does not make the squiggles go away. In that case you’ll need to add a
cpp.hint file to your project that simplifies the UE4 macros for Visual Studio.
OK, that was probably way more than you bargained for. I hope it helps, though.