templated and custom-named classes support and test
parent
0ddef6ed96
commit
e2402d8bfb
|
@ -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: \
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue