-
Notifications
You must be signed in to change notification settings - Fork 43
Templated types and functions
Unreal.hx supports defining externs to C++ templated non-uobject types.
Their extern declaration is very simple and close to how one would declare a generic type in Haxe:
// Example C++ template
template<class T>
class TMyTemplate {
public:
TMyTemplate() { }
};
Will be externed as:
@:glueCppIncludes('path/to/include.h')
@:uextern extern class TMyTemplate<T> {
}
To actually be able to do something useful with this class, one probably would want to create a constructor. If you recall from the Extern definitions section, non-uobject constructors in ue4hx are just static functions with the @:uname("new")
metadata - which brings us to the next section
Like templated classes declarations, declaring a templated function extern is very easy:
@:uname(".ctor") public static function create<T>():TMyTemplate<T>;
The Extern baker will take care of generating the function correctly.
Unlike C++, Haxe doesn't allow you to call a templated function with an explicit type parameter; Rather, all type parameters are inferred by the call. Unfortunately not all C++ function calls can have their type parameter inferred from its arguments/return type, or this inference can become very difficult.
Because of this, the Extern baker will generate some optional helpers to help Haxe infer the function correctly.
These helpers are of the unreal.TypeParam<>
type, and they are no-ops that only help typing. They are optional but do not incur in any performance loss when using them.
So suppose we want to create an instance of TMyTemplate<int32>
from the example above. We can do it in two different ways:
// Let haxe inference do its job
var x:TMyTemplate<unreal.Int32> = TMyTemplate.create();
// Use the TypeParam helper
var x = TMyTemplate.create(new unreal.TypeParam<unreal.Int32>());
Now suppose we want to create an instance of TMyTemplate<UObject *>
:
// Let haxe inference do its job
var x:TMyTemplate<unreal.UObject> = TMyTemplate.create();
// Use the TypeParam helper
var x = TMyTemplate.create(new unreal.TypeParam<unreal.UObject>());
ue4hx is smart enough to know that uobject
-derived types are always used as pointers, not by reference, so it will add the pointer automatically.
However, in some cases we do want uobject
-derived types to be called without a pointer. For example, on the global NewObject<>
templated call - it needs to take the actual UObject type name instead of the expected type.
In this case, you must use the special @:typeName
metadata:
@:typeName @:global public static function NewObject<T>():PExternal<T>; // PExternal indicates that the returned type is a pointer
Sometimes, Unreal provides a templated function that provides no other benefit than allowing one to not have to call .Cast<>
by themselves. For example, DuplicateObject
works just as well if it's called with a <UObject>
implementation, and the template only helps by already casting the result to the same type as the source. @:noTemplate
allows you to define an extern that is generic on Haxe, but not used as a template in the C++ glue code. This is beneficial because it allows you to still have the benefit of the generic function definition, but without the downsides that come from it, which are the need to perform a C++ compilation every time a new template is used.
DuplicateObject
is defined as such in the Unreal.hx externs:
@:glueCppIncludes("UObject/UObjectGlobals.h")
@:uname("DuplicateObject<UObject>")
@:noTemplate
@:global public static function DuplicateObject<T : UObject>(sourceObject:T, destOuter:UObject, ?name:FName):T;