godotengine / godot-cpp

C++ bindings for the Godot script API
MIT License
1.75k stars 580 forks source link

[Question] How to register methods in template class in GDNative?! #256

Open xDGameStudios opened 5 years ago

xDGameStudios commented 5 years ago

I can't expose template classes to Godot script API and this seems fair as it is not supported by the GDScript language. But I wanted to know if there is a way to register methods that are defined within a templated class, for example. How should I proceed?

Here is a code example: TGraphComponent<G, H> and TArc<V> have methods to be exposed to the GDScript API (but the classes themselves are no to be exposed) and Arc is a empty class acting as a dummy just to be exposed to the GDScript api.

template <typename G, typename H>
class TGraphComponent {

    public:
        int get_id() const;
        /// ...
}

template <typename V>
class TArc : public TGraphComponent<ListDigraph, LemonArc> {

    public:
        Ref<V> get_source() const;
        /// ...
}

class Arc : public Reference, public TArc<Vertex> {
        GODOT_CLASS(Arc, Reference);
}

the only way I got it to work is by reimplementing a redirect to the methods in the Arc class:

1) WORKING

class Arc : public Reference, public TArc<Vertex> {
        GODOT_CLASS(Arc, Reference);

        int get_id() const {
                return TArc::get_id();
        }
        Ref<Vertex> get_source() const {
                return TArc::get_source();
        }
        /// ...

        static void _register_methods();
}

then registering the methods as being Arc's in its _register_methods function. Even though this works seams a little (actually a LOT) too hacky and there should be way to do this. maybe something in the way register_method works that needs to be changed?!

A more logical/intuitive way that could be done but doesn't work, is the one below. All the classes stay the same except for the Arc that registers the methods as their own (without the need to redirect the methods):

2) NOT WORKING

class Arc : public Reference, public TArc<Vertex> {
        GODOT_CLASS(Arc, Reference);

        static void _register_methods() {
                register_method("get_id", &Arc::get_id);
                register_method("get_source", &Arc::get_id);
        }
}

However this throws an error at compile time: error: no member named '___get_type_name' in 'godot::TGraphComponent<godot::ListDigraph, lemon::ListDigraphBase::Arc>'

Is there way to do this?! If so how can I do it? If not then it could be a feature to add. Don't know how much of a change it would require but seems pretty "simple" (I'm no C++ expert so don't judge me 😄). It's legal C++ code and we are not trying to expose the templated classes. And it's nothing that is not supported completely as proven by the workaround on example 1).

xDGameStudios commented 5 years ago

@BastiaanOlij sorry for tagging you, but since you seem to have a lot of knowledge on C++. hope you could drop some of your knowledge :) thank you in advance

raymoo commented 5 years ago

I don't think it even works to give a member function pointer from a non-template base class.

raymoo commented 5 years ago

Does trying the workaround in https://github.com/GodotNativeTools/godot-cpp/issues/303#issuecomment-500611318 help?