From e2402d8bfb67c95a66e7dcae73a0c0b86e3da7df Mon Sep 17 00:00:00 2001 From: Vano Date: Wed, 17 Jan 2024 16:56:55 +0200 Subject: [PATCH] templated and custom-named classes support and test --- include/godot_cpp/classes/wrapped.hpp | 35 +++++++++++++++++++++++---- test/project/main.gd | 4 +++ test/src/example.cpp | 18 ++++++++++++++ test/src/example.h | 16 ++++++++++++ test/src/register_types.cpp | 3 +++ 5 files changed, 71 insertions(+), 5 deletions(-) diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index f8f921b3..ef90de69 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -142,10 +142,9 @@ struct EngineClassRegistration { #define _GDCLASS_RECREATE(m_class, m_inherits) return nullptr; #endif -// Use this on top of your own classes. // Note: the trail of `***` is to keep sane diffs in PRs, because clang-format otherwise moves every `\` which makes // every line of the macro different -#define GDCLASS(m_class, m_inherits) /***********************************************************************************************************************************************/ \ +#define GDCLASS_NAME(m_class, m_inherits, m_class_name) /****************************************************************************************************************************/ \ private: \ void operator=(const m_class &p_rval) {} \ friend class ::godot::ClassDB; \ @@ -196,9 +195,9 @@ protected: return (::godot::String(::godot::Wrapped::*)() const) & m_class::_to_string; \ } \ \ - template \ + template \ static void register_virtuals() { \ - m_inherits::register_virtuals(); \ + m_inherits::register_virtuals(); \ } \ \ public: \ @@ -218,7 +217,7 @@ public: } \ \ static ::godot::StringName &get_class_static() { \ - static ::godot::StringName string_name = ::godot::StringName(#m_class); \ + static ::godot::StringName string_name = ::godot::StringName(m_class_name); \ return string_name; \ } \ \ @@ -369,6 +368,32 @@ public: \ private: +// Use this on top of your own classes. +#define GDCLASS(m_class, m_inherits) GDCLASS_NAME(m_class, m_inherits, #m_class) + +/* Use this to create templated class +You need to initialize `static const char *_template_class_name` with custom name +outside of class for every template instatiation you use + +Example: + +// in .h: +template +class ExampleTemplated : public Object { + GDCLASS_TEMPLATED(ExampleTemplated, Object); +}; + +// in .cpp: +template<> +const char * ExampleTemplated::_template_class_name = "ExampleTemplatedInt"; +template<> +const char * ExampleTemplated::_template_class_name = "ExampleTemplatedFloat"; +*/ +#define GDCLASS_TEMPLATE(m_class, m_inherits) /*************************/ \ +private: \ + static const char *_template_class_name; \ + GDCLASS_NAME(m_class, m_inherits, _template_class_name) + // Don't use this for your classes, use GDCLASS() instead. #define GDEXTENSION_CLASS_ALIAS(m_class, m_alias_for, m_inherits) /******************************************************************************************************************/ \ private: \ diff --git a/test/project/main.gd b/test/project/main.gd index 59cab6dc..ce695726 100644 --- a/test/project/main.gd +++ b/test/project/main.gd @@ -241,6 +241,10 @@ func _ready(): assert_equal(new_example_ref.was_post_initialized(), true) assert_equal(example.test_post_initialize(), true) + # Check templated classes + var i = ExampleTemplatedInt.new() + var f = ExampleTemplatedFloat.new() + assert_equal(i.get_number() == 42 and is_equal_approx(f.get_number(), 42), true) exit_with_status() func _on_Example_custom_signal(signal_name, value): diff --git a/test/src/example.cpp b/test/src/example.cpp index 5372d70a..0e56180c 100644 --- a/test/src/example.cpp +++ b/test/src/example.cpp @@ -626,3 +626,21 @@ void Example::_input(const Ref &event) { emit_custom_signal(String("_input: ") + key_event->get_key_label(), key_event->get_unicode()); } } + +template <> +const char *ExampleTemplated::_template_class_name = "ExampleTemplatedInt"; +template class ExampleTemplated; + +template <> +const char *ExampleTemplated::_template_class_name = "ExampleTemplatedFloat"; +template class ExampleTemplated; + +template +void ExampleTemplated::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_number"), &ExampleTemplated::get_number); +} + +template +T ExampleTemplated::get_number() { + return number; +} diff --git a/test/src/example.h b/test/src/example.h index 72f6783d..ba1fb622 100644 --- a/test/src/example.h +++ b/test/src/example.h @@ -205,4 +205,20 @@ protected: static void _bind_methods() {} }; +template +class ExampleTemplated : public Object { + GDCLASS_TEMPLATE(ExampleTemplated, Object); + + T number = (T)42; + +protected: + static void _bind_methods(); + + T get_number(); +}; + +// To suppress warning: instantiation of variable 'ExampleTemplated::_template_class_name' required here, but no definition is available [-Wundefined-var-template] +template +const char *ExampleTemplated::_template_class_name; + #endif // EXAMPLE_CLASS_H diff --git a/test/src/register_types.cpp b/test/src/register_types.cpp index dbb37d90..2e55c444 100644 --- a/test/src/register_types.cpp +++ b/test/src/register_types.cpp @@ -26,6 +26,9 @@ void initialize_example_module(ModuleInitializationLevel p_level) { ClassDB::register_class(); ClassDB::register_class(true); ClassDB::register_abstract_class(); + + ClassDB::register_class>(); + ClassDB::register_class>(); } void uninitialize_example_module(ModuleInitializationLevel p_level) {