templated and custom-named classes support and test

pull/1362/head
Vano 2024-01-17 16:56:55 +02:00
parent 0ddef6ed96
commit e2402d8bfb
5 changed files with 71 additions and 5 deletions

View File

@ -142,10 +142,9 @@ struct EngineClassRegistration {
#define _GDCLASS_RECREATE(m_class, m_inherits) return nullptr; #define _GDCLASS_RECREATE(m_class, m_inherits) return nullptr;
#endif #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 // 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 // every line of the macro different
#define GDCLASS(m_class, m_inherits) /***********************************************************************************************************************************************/ \ #define GDCLASS_NAME(m_class, m_inherits, m_class_name) /****************************************************************************************************************************/ \
private: \ private: \
void operator=(const m_class &p_rval) {} \ void operator=(const m_class &p_rval) {} \
friend class ::godot::ClassDB; \ friend class ::godot::ClassDB; \
@ -196,9 +195,9 @@ protected:
return (::godot::String(::godot::Wrapped::*)() const) & m_class::_to_string; \ return (::godot::String(::godot::Wrapped::*)() const) & m_class::_to_string; \
} \ } \
\ \
template <class T, class B> \ template <class GODOTCPP_T, class GODOTCPP_B> \
static void register_virtuals() { \ static void register_virtuals() { \
m_inherits::register_virtuals<T, B>(); \ m_inherits::register_virtuals<GODOTCPP_T, GODOTCPP_B>(); \
} \ } \
\ \
public: \ public: \
@ -218,7 +217,7 @@ public:
} \ } \
\ \
static ::godot::StringName &get_class_static() { \ 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; \ return string_name; \
} \ } \
\ \
@ -369,6 +368,32 @@ public:
\ \
private: 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 T>
class ExampleTemplated : public Object {
GDCLASS_TEMPLATED(ExampleTemplated, Object);
};
// in .cpp:
template<>
const char * ExampleTemplated<int>::_template_class_name = "ExampleTemplatedInt";
template<>
const char * ExampleTemplated<float>::_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. // Don't use this for your classes, use GDCLASS() instead.
#define GDEXTENSION_CLASS_ALIAS(m_class, m_alias_for, m_inherits) /******************************************************************************************************************/ \ #define GDEXTENSION_CLASS_ALIAS(m_class, m_alias_for, m_inherits) /******************************************************************************************************************/ \
private: \ private: \

View File

@ -241,6 +241,10 @@ func _ready():
assert_equal(new_example_ref.was_post_initialized(), true) assert_equal(new_example_ref.was_post_initialized(), true)
assert_equal(example.test_post_initialize(), 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() exit_with_status()
func _on_Example_custom_signal(signal_name, value): func _on_Example_custom_signal(signal_name, value):

View File

@ -626,3 +626,21 @@ void Example::_input(const Ref<InputEvent> &event) {
emit_custom_signal(String("_input: ") + key_event->get_key_label(), key_event->get_unicode()); emit_custom_signal(String("_input: ") + key_event->get_key_label(), key_event->get_unicode());
} }
} }
template <>
const char *ExampleTemplated<int>::_template_class_name = "ExampleTemplatedInt";
template class ExampleTemplated<int>;
template <>
const char *ExampleTemplated<float>::_template_class_name = "ExampleTemplatedFloat";
template class ExampleTemplated<float>;
template <class T>
void ExampleTemplated<T>::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_number"), &ExampleTemplated::get_number);
}
template <class T>
T ExampleTemplated<T>::get_number() {
return number;
}

View File

@ -205,4 +205,20 @@ protected:
static void _bind_methods() {} static void _bind_methods() {}
}; };
template <class T>
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<int>::_template_class_name' required here, but no definition is available [-Wundefined-var-template]
template <typename T>
const char *ExampleTemplated<T>::_template_class_name;
#endif // EXAMPLE_CLASS_H #endif // EXAMPLE_CLASS_H

View File

@ -26,6 +26,9 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
ClassDB::register_class<Example>(); ClassDB::register_class<Example>();
ClassDB::register_class<ExampleVirtual>(true); ClassDB::register_class<ExampleVirtual>(true);
ClassDB::register_abstract_class<ExampleAbstract>(); ClassDB::register_abstract_class<ExampleAbstract>();
ClassDB::register_class<ExampleTemplated<int>>();
ClassDB::register_class<ExampleTemplated<float>>();
} }
void uninitialize_example_module(ModuleInitializationLevel p_level) { void uninitialize_example_module(ModuleInitializationLevel p_level) {