For some USTRUCT structs
within UnrealEngine, type traits TStructOpsTypeTraits<T>
are defined. These provide a list of bools (encapsulated in an enumeration) about the implemented capabilities of struct T
.
USTRUCT
s within my project?*Example usage from within the Engine:
struct TStructOpsTypeTraitsBase2
{
enum
{
WithZeroConstructor = false, // struct can be constructed as a valid object by filling its memory footprint with zeroes.
WithNoInitConstructor = false, // struct has a constructor which takes an EForceInit parameter which will force the constructor to perform initialization, where the default constructor performs 'uninitialization'.
WithNoDestructor = false, // struct will not have its destructor called when it is destroyed.
WithCopy = !TIsPODType<CPPSTRUCT>::Value, // struct can be copied via its copy assignment operator.
// ...
}
}
Which is used like
template<>
struct TStructOpsTypeTraits<FGameplayEffectContextHandle> : public TStructOpsTypeTraitsBase2<FGameplayEffectContextHandle>
{
enum
{
WithCopy = true, // Necessary so that TSharedPtr<FGameplayEffectContext> Data is copied around
WithNetSerializer = true,
WithIdenticalViaEquality = true,
};
};
It seems that traits are used for USTRUCT
s that are used in blueprints; and that they are required for structs which have a NetSerialize()
function. I made spot checks:
WithIdenticalViaEquality
-> UScriptStruct::HasIdentical()
-> EStructFlags::STRUCT_IdenticalNative
is used only in ::IdenticalHelper()
which is intended for BlueprintsEStructFlags::STRUCT_NetSerializeNative
is used for error messages (when the structs are used in blueprints) and in FObjectReplicator
and FRepLayout
, where this trait is required to be present for custom property replicationthe description of TStructOpsTypeTraitsBase2
seems to tell, that these traits are only important, when the USTRUCT
s are used within blueprints
type traits to cover the custom aspects of a script struct
UnrealEngine defines also a number of specialized traits for its container classes (e.g. TTypeTraitsBase
). A comparison with c++ type_traits might be meaningful.
Many of the features available "out-of-the-box" in Unreal Engine 4 (e.g. replication, initialization, serialization, etc.) rely on information specific to each class. This allows different classes to - for example - customize how to serialize their own data.
For classes inheriting from the base UObject
class, all the needed information are stored into properties or returned by overridable methods. For example, if you want to customize how your UObject-derived class manages serialization, you can simply override its virtual Serialize()
method. This is enough for UE4 to be able to invoke your custom implementation when it need to serialize an instance of your class.
The problem with structs in UE4, is that they don't inherit from a common base class/interface. So UE4 doesn't have any pre-declare property or method to call. Trying to call an undeclared method will of course cause a compilation error in C++. Following the previous example on the custom serialization - UE4 can't in general invoke the Serialize() method on structs because some/most of them will not have such method and the compiler will report it as an error.
TStructOpsTypeTraitsBase2
is the solution to the above problem. You declare a specialization of it for your custom structs to inform UE4 of which methods are available. When done, using a mix of template meta-programming and auto-generated code, UE4 will be able to call such methods to provide again out-of-the-box services or allow you to customize default behaviors. For example, declaring WithSerializer = true
you're informing UE4 that your struct has a custom Serialize()
method and so UE4 will be able to automatically call it every time it needs to serialize an instance of your struct.
TStructOpsTypeTraitsBase2
is not limited to structs used with Blueprints, but is used also with USTRUCT()
used in C++.
On when to use it, you need to declare a custom specialization of TStructOpsTypeTraitsBase2
when the default behavior of UE4 on your structure is not what you want (e.g. you want to serialize its data in a different way while the default implementation serializes all the not-transient UPROPERTY()
using "standard" formats).
While the "form" is similar, the scope of TStructOpsTypeTraitsBase2
is different than C++ type_traits
: type_traits
is used by the compiler to inform the program/programmer about platform characteristics. TStructOpsTypeTraitsBase2
is used by the programmer to inform UE4 about available "extra" features of a custom struct.