UHT Core Type Restrictions

Hello,

We’ve developed some specialized core data types tailored to our project’s needs -- nothing unusual there. These types follow the same design conventions as the engine’s built-in types (templating, vectorization, and a Blueprint-exposed USTRUCT “shell”). Everything works fine except for one detail: the “IsCoreType” USTRUCT() property is restricted to NoExportTypes.h

From what we can tell, “IsCoreType” simply prevents the type from being declared, and might be more appropriately named “NoDeclaration.” We’re curious about the rationale behind restricting its use for engine-only types. Is there a particular reason why this functionality is off-limits for external developers? We’ve tested removing that restriction and haven’t noticed any issues or side effects so far.

Could you provide any insight into whether it’s safe to use “IsCoreType” in our own custom types, or if there’s a specific reason it’s not intended for public use? If not, we’d love to make a simple PR for it.

Thanks,

Blake

Hi Blake,

The IsCoreType attribute was added to maintain parity with the generated code that C++ UHT produced, while we were still in the transition period to C#. As C++ UHT no longer exists, there is no use for the attribute now and will be removed in the future.

However, your specialised types shouldn’t require it either. Have you encountered any problems that required you to specify it?

Steve

Hi Steve,

Thanks for your reply. Considering our core types are templated, there is no way to expose them to UHT that we know of, which is why are have “shadow” structs and are exposed to UTH with “IsCoreType.” Again, this is exactly how the engine setups its core types.

Are you saying there is an alternate method to having C++ templated types exposed to the engine/editor through UHT? If so, I’d be very interested to understand how that can be accomplished. If we remove the “IsCoreType” now from our shadow structs we get redefinition errors, since our C++ forward declares the type and now the USTRUCT() also declares it in the gen file. If we enable “IsCoreType” on the USTRUCT() then everything compiles fine because it instructs UHT to not forward declare the struct in the gen file.

Thanks,

Blake

Hi Blake,

I’m not suggesting there is an alternative way to expose your types to the engine, I was asking why you feel the need to add the IsCoreType specifier to your types. If your types are typedefs of templates, then I can see how that would cause problems.

I don’t anticipate you would have any problems if you remove that restriction and use it on your types. If we do revisit the purpose of that specifier, it might be to deprecate it and instead specify the ‘real type’ that it is a typedef of, in which case you’d get deprecation warnings and time to fix things up.

Hope this helps,

Steve

Hi Steve,

Thanks again for your reply. Our types are indeed typedefs of templates, just like the engine handles it’s core types. Adding IsCoreType is required for us on the USTRUCT() in order to compile, otherwise the forward declare that UHT generates causes a redefinition error. You can see this in the code snippet below.

`// OurTransform.h

template<typename T, typename U>
struct TOurTransform {};

// OurFwd.h

using FOurTransform = TOurTransform<double, int64>;

// OurNoExportTypes.h

USTRUCT(BlueprintType, IsCoreType, NoExport)
struct FOurTransform {};`Because IsCoreType is restricted to only files named “NoExportTypes.h” the above fails to compile without the removal of that restriction (which is on line 77 of UhtScriptStructSpecifiers.cs). If we just try removing IsCoreType from the USTRUCT(), we then get errors when trying to use that type as UHT will forward declare it at the top of its generated file (resulting in a redefinition). You can see this behavior on line 109 of UhtStructProperty.cs. The solution for us is simply to remove the restriction that UHT has for that specifier. The question we have is why that restriction is there in the first place. I assume it was just part of the thought-process at the time the core types were coded for the engine.

It is good to hear that you do not anticipate any issues with removing the UHT restriction on IsCoreType. Our experience so far is that removing the restriction works just fine. If that specifier is to be changed/deprecated in the future, we are happy to handle warnings or incompatibilities at that time. A new specifier that directly specifies the “real type” would indeed be an improvement imo. Our wish is simply that this specifier (or whatever replaces it) be allowed/usable to developers who want to achieve similar behavior for how the engine is able to template and typedef it’s core types while still exposing them to UHT and thus Blueprints.

Thanks,

Blake

Hi Blake,

I had misinterpreted the original reason for the specifier. If it wasn’t for typedefs, they shouldn’t be needed. The specifier was never intended for non-Epic code, which is why it’s limited to NoExportTypes.h. I am not saying it is deprecated, but rather it may be made so in future because I think it reflects intent poorly - a better specifier would be to add something like TemplateAlias=“UE::Math::TVector<double>” so that it can be declared correctly in generated code and usable outside of NoExportTypes.h, in which case the IsCoreType specifier would be deprecated. I will discuss it with the owner of UHT.

Steve

Hi Steve,

Yes, agreed on all fronts. I look forward to TemplateAlias or something similar in the future. Thanks for discussing it with the UHT owner.

Thanks,

Blake