diff --git a/engine/asset/objects/character/player/player.object.json b/engine/asset/objects/character/player/player.object.json index 1a16e93e7..fdf66e2cc 100644 --- a/engine/asset/objects/character/player/player.object.json +++ b/engine/asset/objects/character/player/player.object.json @@ -124,7 +124,7 @@ }, { "$context": { - "lua_script": "if (get_bool(GameObject, \"MotorComponent.m_is_moving\")) then set_float(GameObject, \"MotorComponent.m_motor_res.m_jump_height\", 10) else set_float(GameObject, \"MotorComponent.m_motor_res.m_jump_height\", 5) end" + "lua_script": "if (get_bool(GameObject, \"MotorComponent.m_is_moving\")) then set_float(GameObject, \"MotorComponent.m_motor_res.m_jump_height\", 10) else set_float(GameObject, \"MotorComponent.m_motor_res.m_jump_height\", 5) end invoke(GameObject, \"MotorComponent.getOffStuckDead\")" }, "$typeName": "LuaComponent" } diff --git a/engine/source/meta_parser/parser/generator/generator.cpp b/engine/source/meta_parser/parser/generator/generator.cpp index e7d62035b..b1cf20e9b 100644 --- a/engine/source/meta_parser/parser/generator/generator.cpp +++ b/engine/source/meta_parser/parser/generator/generator.cpp @@ -35,6 +35,11 @@ namespace Generator Mustache::data class_field_defines = Mustache::data::type::list; genClassFieldRenderData(class_temp, class_field_defines); class_def.set("class_field_defines", class_field_defines); + + + Mustache::data class_method_defines = Mustache::data::type::list; + genClassMethodRenderData(class_temp, class_method_defines); + class_def.set("class_method_defines", class_method_defines); } void GeneratorInterface::genClassFieldRenderData(std::shared_ptr class_temp, Mustache::data& feild_defs) { @@ -54,4 +59,17 @@ namespace Generator feild_defs.push_back(filed_define); } } + + void GeneratorInterface::genClassMethodRenderData(std::shared_ptr class_temp, Mustache::data& method_defs) + { + for (auto& method : class_temp->m_methods) + { + if (!method->shouldCompile()) + continue; + Mustache::data method_define; + + method_define.set("class_method_name", method->m_name); + method_defs.push_back(method_define); + } + } } // namespace Generator diff --git a/engine/source/meta_parser/parser/generator/generator.h b/engine/source/meta_parser/parser/generator/generator.h index 40ba9e5a8..52fb8497d 100644 --- a/engine/source/meta_parser/parser/generator/generator.h +++ b/engine/source/meta_parser/parser/generator/generator.h @@ -20,9 +20,11 @@ namespace Generator virtual ~GeneratorInterface() {}; protected: - virtual void prepareStatus(std::string path); - virtual void genClassRenderData(std::shared_ptr class_temp, Mustache::data& class_def); - virtual void genClassFieldRenderData(std::shared_ptr class_temp, Mustache::data& feild_defs); + virtual void prepareStatus(std::string path); + virtual void genClassRenderData(std::shared_ptr class_temp, Mustache::data& class_def); + virtual void genClassFieldRenderData(std::shared_ptr class_temp, Mustache::data& feild_defs); + virtual void genClassMethodRenderData(std::shared_ptr class_temp, Mustache::data& method_defs); + virtual std::string processFileName(std::string path) = 0; std::string m_out_path {"gen_src"}; diff --git a/engine/source/meta_parser/parser/generator/reflection_generator.cpp b/engine/source/meta_parser/parser/generator/reflection_generator.cpp index eb2c078d8..7f7a530e5 100644 --- a/engine/source/meta_parser/parser/generator/reflection_generator.cpp +++ b/engine/source/meta_parser/parser/generator/reflection_generator.cpp @@ -47,7 +47,7 @@ namespace Generator // class defs for (auto class_temp : schema.classes) { - if (!class_temp->shouldCompileFilds()) + if (!class_temp->shouldCompile()) continue; class_names.insert_or_assign(class_temp->getClassName(), false); diff --git a/engine/source/meta_parser/parser/generator/serializer_generator.cpp b/engine/source/meta_parser/parser/generator/serializer_generator.cpp index 3019c2aa8..cce485f1a 100644 --- a/engine/source/meta_parser/parser/generator/serializer_generator.cpp +++ b/engine/source/meta_parser/parser/generator/serializer_generator.cpp @@ -37,7 +37,7 @@ namespace Generator Mustache::data("headfile_name", Utils::makeRelativePath(m_root_path, path).string())); for (auto class_temp : schema.classes) { - if (!class_temp->shouldCompileFilds()) + if (!class_temp->shouldCompileFields()) continue; Mustache::data class_def; diff --git a/engine/source/meta_parser/parser/language_types/class.cpp b/engine/source/meta_parser/parser/language_types/class.cpp index 59a18c745..f1c6599fa 100644 --- a/engine/source/meta_parser/parser/language_types/class.cpp +++ b/engine/source/meta_parser/parser/language_types/class.cpp @@ -26,20 +26,29 @@ Class::Class(const Cursor& cursor, const Namespace& current_namespace) : case CXCursor_FieldDecl: m_fields.emplace_back(new Field(child, current_namespace, this)); break; + // method + case CXCursor_CXXMethod: + m_methods.emplace_back(new Method(child, current_namespace, this)); default: break; } } } -bool Class::shouldCompile(void) const { return shouldCompileFilds(); } +bool Class::shouldCompile(void) const { return shouldCompileFields()|| shouldCompileMethods(); } -bool Class::shouldCompileFilds(void) const +bool Class::shouldCompileFields(void) const { return m_meta_data.getFlag(NativeProperty::All) || m_meta_data.getFlag(NativeProperty::Fields) || m_meta_data.getFlag(NativeProperty::WhiteListFields); } +bool Class::shouldCompileMethods(void) const{ + + return m_meta_data.getFlag(NativeProperty::All) || m_meta_data.getFlag(NativeProperty::Methods) || + m_meta_data.getFlag(NativeProperty::WhiteListMethods); +} + std::string Class::getClassName(void) { return m_name; } bool Class::isAccessible(void) const { return m_enabled; } \ No newline at end of file diff --git a/engine/source/meta_parser/parser/language_types/class.h b/engine/source/meta_parser/parser/language_types/class.h index c2902002e..502b8512e 100644 --- a/engine/source/meta_parser/parser/language_types/class.h +++ b/engine/source/meta_parser/parser/language_types/class.h @@ -3,6 +3,7 @@ #include "type_info.h" #include "field.h" +#include "method.h" struct BaseClass { @@ -15,6 +16,7 @@ class Class : public TypeInfo { // to access m_qualifiedName friend class Field; + friend class Method; friend class MetaParser; public: @@ -22,7 +24,8 @@ class Class : public TypeInfo virtual bool shouldCompile(void) const; - bool shouldCompileFilds(void) const; + bool shouldCompileFields(void) const; + bool shouldCompileMethods(void) const; template using SharedPtrVector = std::vector>; @@ -37,6 +40,7 @@ class Class : public TypeInfo std::string m_qualified_name; SharedPtrVector m_fields; + SharedPtrVector m_methods; std::string m_display_name; diff --git a/engine/source/meta_parser/parser/language_types/method.cpp b/engine/source/meta_parser/parser/language_types/method.cpp new file mode 100644 index 000000000..f8eea942b --- /dev/null +++ b/engine/source/meta_parser/parser/language_types/method.cpp @@ -0,0 +1,19 @@ +#include "common/precompiled.h" + +#include "class.h" +#include "method.h" + +Method::Method(const Cursor& cursor, const Namespace& current_namespace, Class* parent) : + TypeInfo(cursor, current_namespace), m_parent(parent), m_name(cursor.getSpelling()) +{} + +bool Method::shouldCompile(void) const { return isAccessible(); } + +bool Method::isAccessible(void) const +{ + return ((m_parent->m_meta_data.getFlag(NativeProperty::Methods) || + m_parent->m_meta_data.getFlag(NativeProperty::All)) && + !m_meta_data.getFlag(NativeProperty::Disable)) || + (m_parent->m_meta_data.getFlag(NativeProperty::WhiteListMethods) && + m_meta_data.getFlag(NativeProperty::Enable)); +} diff --git a/engine/source/meta_parser/parser/language_types/method.h b/engine/source/meta_parser/parser/language_types/method.h new file mode 100644 index 000000000..98236e45d --- /dev/null +++ b/engine/source/meta_parser/parser/language_types/method.h @@ -0,0 +1,24 @@ +#pragma once + +#include "type_info.h" + +class Class; + +class Method : public TypeInfo +{ + +public: + Method(const Cursor& cursor, const Namespace& current_namespace, Class* parent = nullptr); + + virtual ~Method(void) {} + + bool shouldCompile(void) const; + +public: + + Class* m_parent; + + std::string m_name; + + bool isAccessible(void) const; +}; \ No newline at end of file diff --git a/engine/source/meta_parser/parser/meta/meta_data_config.h b/engine/source/meta_parser/parser/meta/meta_data_config.h index 329816374..e30ce5820 100644 --- a/engine/source/meta_parser/parser/meta/meta_data_config.h +++ b/engine/source/meta_parser/parser/meta/meta_data_config.h @@ -5,10 +5,12 @@ namespace NativeProperty const auto All = "All"; const auto Fields = "Fields"; + const auto Methods = "Methods"; const auto Enable = "Enable"; const auto Disable = "Disable"; const auto WhiteListFields = "WhiteListFields"; + const auto WhiteListMethods = "WhiteListMethods"; } // namespace NativeProperty diff --git a/engine/source/runtime/core/meta/reflection/reflection.cpp b/engine/source/runtime/core/meta/reflection/reflection.cpp index f31e0d614..43193f0f3 100644 --- a/engine/source/runtime/core/meta/reflection/reflection.cpp +++ b/engine/source/runtime/core/meta/reflection/reflection.cpp @@ -9,15 +9,19 @@ namespace Piccolo const char* k_unknown_type = "UnknownType"; const char* k_unknown = "Unknown"; - static std::map m_class_map; - static std::multimap m_field_map; - static std::map m_array_map; + static std::map m_class_map; + static std::multimap m_field_map; + static std::multimap m_method_map; + static std::map m_array_map; void TypeMetaRegisterinterface::registerToFieldMap(const char* name, FieldFunctionTuple* value) { m_field_map.insert(std::make_pair(name, value)); } - + void TypeMetaRegisterinterface::registerToMethodMap(const char* name, MethodFunctionTuple* value) + { + m_method_map.insert(std::make_pair(name, value)); + } void TypeMetaRegisterinterface::registerToArrayMap(const char* name, ArrayFunctionTuple* value) { if (m_array_map.find(name) == m_array_map.end()) @@ -65,6 +69,7 @@ namespace Piccolo { m_is_valid = false; m_fields.clear(); + m_methods.clear(); auto fileds_iter = m_field_map.equal_range(type_name); while (fileds_iter.first != fileds_iter.second) @@ -75,9 +80,19 @@ namespace Piccolo ++fileds_iter.first; } + + auto methods_iter = m_method_map.equal_range(type_name); + while (methods_iter.first != methods_iter.second) + { + MethodAccessor f_method(methods_iter.first->second); + m_methods.emplace_back(f_method); + m_is_valid = true; + + ++methods_iter.first; + } } - TypeMeta::TypeMeta() : m_type_name(k_unknown_type), m_is_valid(false) { m_fields.clear(); } + TypeMeta::TypeMeta() : m_type_name(k_unknown_type), m_is_valid(false) { m_fields.clear(); m_methods.clear(); } TypeMeta TypeMeta::newMetaFromName(std::string type_name) { @@ -134,6 +149,17 @@ namespace Piccolo return count; } + int TypeMeta::getMethodsList(MethodAccessor*& out_list) + { + int count = m_methods.size(); + out_list = new MethodAccessor[count]; + for (int i = 0; i < count; ++i) + { + out_list[i] = m_methods[i]; + } + return count; + } + int TypeMeta::getBaseClassReflectionInstanceList(ReflectionInstance*& out_list, void* instance) { auto iter = m_class_map.find(m_type_name); @@ -156,6 +182,16 @@ namespace Piccolo return FieldAccessor(nullptr); } + MethodAccessor TypeMeta::getMethodByName(const char* name) + { + const auto it = std::find_if(m_methods.begin(), m_methods.end(), [&](const auto& i) { + return std::strcmp(i.getMethodName(), name) == 0; + }); + if (it != m_methods.end()) + return *it; + return MethodAccessor(nullptr); + } + TypeMeta& TypeMeta::operator=(const TypeMeta& dest) { if (this == &dest) @@ -165,6 +201,10 @@ namespace Piccolo m_fields.clear(); m_fields = dest.m_fields; + + m_methods.clear(); + m_methods = dest.m_methods; + m_type_name = dest.m_type_name; m_is_valid = dest.m_is_valid; @@ -237,6 +277,36 @@ namespace Piccolo return *this; } + MethodAccessor::MethodAccessor() + { + m_method_name = k_unknown; + m_functions = nullptr; + } + + MethodAccessor::MethodAccessor(MethodFunctionTuple* functions) : m_functions(functions) + { + m_method_name = k_unknown; + if (m_functions == nullptr) + { + return; + } + + m_method_name = (std::get<0>(*m_functions))(); + } + const char* MethodAccessor::getMethodName() const{ + return (std::get<0>(*m_functions))(); + } + MethodAccessor& MethodAccessor::operator=(const MethodAccessor& dest) + { + if (this == &dest) + { + return *this; + } + m_functions = dest.m_functions; + m_method_name = dest.m_method_name; + return *this; + } + void MethodAccessor::invoke(void* instance) { (std::get<1>(*m_functions))(instance); } ArrayAccessor::ArrayAccessor() : m_func(nullptr), m_array_type_name("UnKnownType"), m_element_type_name("UnKnownType") {} diff --git a/engine/source/runtime/core/meta/reflection/reflection.h b/engine/source/runtime/core/meta/reflection/reflection.h index fa9d9d8bd..f92fe2ffd 100644 --- a/engine/source/runtime/core/meta/reflection/reflection.h +++ b/engine/source/runtime/core/meta/reflection/reflection.h @@ -37,6 +37,7 @@ namespace Piccolo }; #define REGISTER_FIELD_TO_MAP(name, value) TypeMetaRegisterinterface::registerToFieldMap(name, value); +#define REGISTER_Method_TO_MAP(name, value) TypeMetaRegisterinterface::registerToMethodMap(name, value); #define REGISTER_BASE_CLASS_TO_MAP(name, value) TypeMetaRegisterinterface::registerToClassMap(name, value); #define REGISTER_ARRAY_TO_MAP(name, value) TypeMetaRegisterinterface::registerToArrayMap(name, value); #define UNREGISTER_ALL TypeMetaRegisterinterface::unregisterAll(); @@ -52,11 +53,12 @@ namespace Piccolo *static_cast(dst_ptr) = *static_cast(src_ptr.getPtr()); #define TypeMetaDef(class_name, ptr) \ - Piccolo::Reflection::ReflectionInstance(Piccolo::Reflection::TypeMeta::newMetaFromName(#class_name), (class_name*)ptr) + Piccolo::Reflection::ReflectionInstance(Piccolo::Reflection::TypeMeta::newMetaFromName(#class_name), \ + (class_name*)ptr) #define TypeMetaDefPtr(class_name, ptr) \ new Piccolo::Reflection::ReflectionInstance(Piccolo::Reflection::TypeMeta::newMetaFromName(#class_name), \ - (class_name*)ptr) + (class_name*)ptr) template struct is_safely_castable : std::false_type @@ -70,6 +72,7 @@ namespace Piccolo { class TypeMeta; class FieldAccessor; + class MethodAccessor; class ArrayAccessor; class ReflectionInstance; } // namespace Reflection @@ -80,16 +83,17 @@ namespace Piccolo typedef std::function GetArrayFunc; typedef std::function GetSizeFunc; typedef std::function GetBoolFunc; + typedef std::function InvokeFunction; - typedef std::function ConstructorWithJson; - typedef std::function WriteJsonByName; + typedef std::function ConstructorWithJson; + typedef std::function WriteJsonByName; typedef std::function GetBaseClassReflectionInstanceListFunc; typedef std::tuple - FieldFunctionTuple; - typedef std::tuple - ClassFunctionTuple; - typedef std::tuple ArrayFunctionTuple; + FieldFunctionTuple; + typedef std::tuple MethodFunctionTuple; + typedef std::tuple ClassFunctionTuple; + typedef std::tuple ArrayFunctionTuple; namespace Reflection { @@ -98,6 +102,8 @@ namespace Piccolo public: static void registerToClassMap(const char* name, ClassFunctionTuple* value); static void registerToFieldMap(const char* name, FieldFunctionTuple* value); + + static void registerToMethodMap(const char* name, MethodFunctionTuple* value); static void registerToArrayMap(const char* name, ArrayFunctionTuple* value); static void unregisterAll(); @@ -117,15 +123,17 @@ namespace Piccolo static bool newArrayAccessorFromName(std::string array_type_name, ArrayAccessor& accessor); static ReflectionInstance newFromNameAndJson(std::string type_name, const Json& json_context); - static Json writeByName(std::string type_name, void* instance); + static Json writeByName(std::string type_name, void* instance); std::string getTypeName(); int getFieldsList(FieldAccessor*& out_list); + int getMethodsList(MethodAccessor*& out_list); int getBaseClassReflectionInstanceList(ReflectionInstance*& out_list, void* instance); FieldAccessor getFieldByName(const char* name); + MethodAccessor getMethodByName(const char* name); bool isValid() { return m_is_valid; } @@ -135,9 +143,9 @@ namespace Piccolo TypeMeta(std::string type_name); private: - std::vector> m_fields; - - std::string m_type_name; + std::vector> m_fields; + std::vector> m_methods; + std::string m_type_name; bool m_is_valid; }; @@ -177,7 +185,26 @@ namespace Piccolo const char* m_field_name; const char* m_field_type_name; }; + class MethodAccessor + { + friend class TypeMeta; + + public: + MethodAccessor(); + + void invoke(void* instance); + const char* getMethodName() const; + + MethodAccessor& operator=(const MethodAccessor& dest); + + private: + MethodAccessor(MethodFunctionTuple* functions); + + private: + MethodFunctionTuple* m_functions; + const char* m_method_name; + }; /** * Function reflection is not implemented, so use this as an std::vector accessor */ diff --git a/engine/source/runtime/function/framework/component/lua/lua_component.cpp b/engine/source/runtime/function/framework/component/lua/lua_component.cpp index 04234d2cf..f6681b520 100644 --- a/engine/source/runtime/function/framework/component/lua/lua_component.cpp +++ b/engine/source/runtime/function/framework/component/lua/lua_component.cpp @@ -82,12 +82,76 @@ namespace Piccolo } } + void LuaComponent::invoke(std::weak_ptr game_object, const char* name) + { + LOG_INFO(name); + + Reflection::TypeMeta meta; + void* target_instance = nullptr; + std::string method_name; + + // get target instance and meta + std::string target_name(name); + size_t pos = target_name.find_last_of('.'); + method_name = target_name.substr(pos + 1, target_name.size()); + target_name = target_name.substr(0, pos); + + if (target_name.find_first_of('.') == target_name.npos) + { + // target is a component + auto components = game_object.lock()->getComponents(); + + auto component_iter = std::find_if( + components.begin(), components.end(), [target_name](auto c) { return c.getTypeName() == target_name; }); + if (component_iter != components.end()) + { + meta = Reflection::TypeMeta::newMetaFromName(target_name); + target_instance = component_iter->getPtr(); + } + else + { + LOG_ERROR("Cand find component"); + return; + } + } + else + { + Reflection::FieldAccessor field_accessor; + if (find_component_field(game_object, name, field_accessor, target_instance)) + { + target_instance = field_accessor.get(target_instance); + field_accessor.getTypeMeta(meta); + } + else + { + LOG_ERROR("Can't find target field."); + return; + } + } + + // invoke function + Reflection::MethodAccessor* methods; + size_t method_count = meta.getMethodsList(methods); + auto method_iter = std::find_if( + methods, methods + method_count, [method_name](auto m) { return m.getMethodName() == method_name; }); + if (method_iter != methods + method_count) + { + method_iter->invoke(target_instance); + } + else + { + LOG_ERROR("Cand find method"); + } + delete[] methods; + } + void LuaComponent::postLoadResource(std::weak_ptr parent_object) { m_parent_object = parent_object; m_lua_state.open_libraries(sol::lib::base); m_lua_state.set_function("set_float", &LuaComponent::set); m_lua_state.set_function("get_bool", &LuaComponent::get); + m_lua_state.set_function("invoke", &LuaComponent::invoke); m_lua_state["GameObject"] = m_parent_object; } diff --git a/engine/source/runtime/function/framework/component/lua/lua_component.h b/engine/source/runtime/function/framework/component/lua/lua_component.h index 6be820006..347a584d5 100644 --- a/engine/source/runtime/function/framework/component/lua/lua_component.h +++ b/engine/source/runtime/function/framework/component/lua/lua_component.h @@ -22,7 +22,8 @@ namespace Piccolo template static T get(std::weak_ptr game_object, const char* name); - protected: + static void invoke(std::weak_ptr game_object, const char* name); + protected: sol::state m_lua_state; META(Enable) std::string m_lua_script; diff --git a/engine/source/runtime/function/framework/component/motor/motor_component.cpp b/engine/source/runtime/function/framework/component/motor/motor_component.cpp index 7c484685f..9a3b8f958 100644 --- a/engine/source/runtime/function/framework/component/motor/motor_component.cpp +++ b/engine/source/runtime/function/framework/component/motor/motor_component.cpp @@ -38,6 +38,7 @@ namespace Piccolo m_target_position = transform_component->getPosition(); } + void MotorComponent::getOffStuckDead() { LOG_INFO("Some get off stuck dead logic"); } MotorComponent::~MotorComponent() { if (m_controller_type == ControllerType::physics) diff --git a/engine/source/runtime/function/framework/component/motor/motor_component.h b/engine/source/runtime/function/framework/component/motor/motor_component.h index 7d589e581..fe06513ea 100644 --- a/engine/source/runtime/function/framework/component/motor/motor_component.h +++ b/engine/source/runtime/function/framework/component/motor/motor_component.h @@ -21,7 +21,7 @@ namespace Piccolo }; REFLECTION_TYPE(MotorComponent) - CLASS(MotorComponent : public Component, WhiteListFields) + CLASS(MotorComponent : public Component, WhiteListFields,WhiteListMethods) { REFLECTION_BODY(MotorComponent) public: @@ -39,6 +39,9 @@ namespace Piccolo float getSpeedRatio() const { return m_move_speed_ratio; } bool getIsMoving() const { return m_is_moving; } + META(Enable) + void getOffStuckDead(); + private: void calculatedDesiredHorizontalMoveSpeed(unsigned int command, float delta_time); void calculatedDesiredVerticalMoveSpeed(unsigned int command, float delta_time); diff --git a/engine/template/commonReflectionFile.mustache b/engine/template/commonReflectionFile.mustache index 2579c074a..f08e50532 100644 --- a/engine/template/commonReflectionFile.mustache +++ b/engine/template/commonReflectionFile.mustache @@ -37,6 +37,12 @@ namespace Reflection{ static void* get_{{class_field_name}}(void* instance){ return static_cast(&(static_cast<{{class_name}}*>(instance)->{{class_field_name}}));} static bool isArray_{{class_field_name}}(){ {{#class_field_is_vector}}return true;{{/class_field_is_vector}}{{^class_field_is_vector}}return false;{{/class_field_is_vector}} } {{/class_field_defines}} + + // methods + {{#class_method_defines}} + static const char* getMethodName_{{class_method_name}}(){ return "{{class_method_name}}";} + static void invoke_{{class_method_name}}(void * instance){static_cast<{{class_name}}*>(instance)->{{class_method_name}}();} + {{/class_method_defines}} }; }//namespace TypeFieldReflectionOparator {{#vector_exist}}namespace ArrayReflectionOperator{ @@ -73,6 +79,13 @@ namespace Reflection{ &TypeFieldReflectionOparator::Type{{class_name}}Operator::isArray_{{class_field_name}}); REGISTER_FIELD_TO_MAP("{{class_name}}", field_function_tuple_{{class_field_name}}); {{/class_field_defines}} + + {{#class_method_defines}} + MethodFunctionTuple* method_function_tuple_{{class_method_name}}=new MethodFunctionTuple( + &TypeFieldReflectionOparator::Type{{class_name}}Operator::getMethodName_{{class_method_name}}, + &TypeFieldReflectionOparator::Type{{class_name}}Operator::invoke_{{class_method_name}}); + REGISTER_Method_TO_MAP("{{class_name}}", method_function_tuple_{{class_method_name}}); + {{/class_method_defines}} {{#vector_exist}}{{#vector_defines}}ArrayFunctionTuple* array_tuple_{{vector_useful_name}} = new ArrayFunctionTuple( &ArrayReflectionOperator::Array{{vector_useful_name}}Operator::set,