Registering Template Types ========================== Constructors and Factories -------------------------- For template types, AngelScript will pass a hidden ``asITypeInfo*`` in the front of arguments, indicating an instantiation of the template. It will be automatically handled by the library with the special binding generators of templated types, which are named ``template_value_class`` and ``template_ref_class``. .. note:: ``asGetTypeTraits()`` cannot determine the type flags for a template value type, because its constructors contain parameters of the hidden ``asITypeInfo*``. As a result, you need to manually pass the flags to the binding generator. This also applies to the ``.behaviours_by_traits()`` helper. Here are examples from the unit tests. .. code-block:: c++ script_array::script_array(asITypeInfo* ti) { /* ... */ } script_array::script_array(asITypeInfo* ti, asUINT n) { /* ... */ } .. code-block:: c++ using namespace asbind20; template_value_class( engine, "optional", asOBJ_GC | asOBJ_APP_CLASS_CDAK | asOBJ_APP_CLASS_MORE_CONSTRUCTORS ); template_ref_class( engine, "array", asOBJ_GC ) .default_factory() // script_array(asITypeInfo*) .factory("uint", use_explicit) // script_array(asITypeInfo*, asUINT) Methods of a Template Class --------------------------- Methods are registered the same way as ordinary types. You can directly use the subtype in the declaration of method. .. code-block:: c++ using namespace asbind20; template_ref_class(/* ... */) .factory("uint n, const T&in value", use_policy) .list_factory("repeat T", use_policy) .method("T& opIndex(uint)", &script_array::opIndex) .method("const T& opIndex(uint) const", &script_array::opIndex); .. note:: If the subtype might be an object handle, you probably need to consider the keyword ``if_handle_then_const``. You can also read `official document explaining this `_ .. code-block:: c++ using namespace asbind20; template_ref_class(/* ... */) .method("array_iterator find(const T&in if_handle_then_const value, int start=0, uint n=uint(-1))". /* ... */); Callback for Validating Template Instantiations =============================================== In order to avoid unnecessary runtime validations of invalid template instantiations, the application should preferably register a validator by ``.template_callback``. Its underlying type behaviour is ``asBEHAVE_TEMPLATE_CALLBACK``. The callback function must be a global function that receives a pointer to ``asITypeInfo*`` as its first parameter, and should return a boolean. If the template instance is valid the return value should be ``true``. The function should also take a second parameter with an output reference to a boolean. This parameter should be set to ``true`` by the function if the template instance should not be garbage collected, which will make AngelScript clear the ``asOBJ_GC`` flag for the object type. If the template instance cannot form any circular references, then it doesn't need to be garbage collected, which reduces the work that has to be done by the garbage collector. :doc:`The tools for handling AngelScript types can help you to deal with validation. ` Example code from the validator of ``script_optional``: .. code-block:: c++ static bool optional_template_callback( asITypeInfo* ti, bool& no_gc ) { int subtype_id = ti->GetSubTypeId(); if(is_void_type(subtype_id)) return false; if(is_primitive_type(subtype_id)) no_gc = true; else no_gc = !type_requires_gc(ti->GetSubType()); return true; } .. code-block:: c++ template_value_class(/* .... */) .template_callback(&optional_template_callback); Template Specializations ======================== When registering a template specialization, you override the template instance that AngelScript would normally create when compiling a declaration with the template type. This allow the application to register a completely different object with its own implementation for template specializations. Template specializations are registered like :doc:`ordinary types `, except the type name should be the instantiated name. .. code-block:: c++ value_class>(engine, "vec2", /* ... */) .method(/* ... */);