godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
88.65k stars 20.11k forks source link

C++ module does not compile if binding a function that returns a class instance #65466

Open markwiering opened 2 years ago

markwiering commented 2 years ago

Godot version

3.6 beta custom build

System information

MX Linux 21.2 64-bit, Mesa Intel(R) Xe Graphics (TGL GT2)

Issue description

When creating a C++ module where the class binds a function that returns a class instance, Godot gives a compilation error. This error is not given when not binding this function.

The error given:

                 from ./core/class_db.h:34,
                 from ./core/reference.h:34,
                 from modules/breuk/breuk.h:4,
                 from modules/breuk/breuk.cpp:8:
./core/method_bind.gen.inc: In instantiation of 'PropertyInfo MethodBind2R<R, P1, P2>::_gen_argument_type_info(int) const [with R = Breuk; P1 = int; P2 = int]':
./core/method_bind.gen.inc:1644:23:   required from here
./core/method_bind.gen.inc:1645:60: error: incomplete type 'GetTypeInfo<Breuk, void>' used in nested name specifier
 1645 |   if (p_argument==-1) return GetTypeInfo<R>::get_class_info();
      |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
./core/method_bind.gen.inc: In instantiation of 'GodotTypeInfo::Metadata MethodBind2R<R, P1, P2>::get_argument_meta(int) const [with R = Breuk; P1 = int; P2 = int]':
./core/method_bind.gen.inc:1627:34:   required from here
./core/method_bind.gen.inc:1628:41: error: incomplete type 'GetTypeInfo<Breuk, void>' used in nested name specifier
 1628 |   if (p_arg==-1) return GetTypeInfo<R>::METADATA;
      |                                         ^~~~~~~~
[ 28%] ./core/method_bind.gen.inc: In instantiation of 'Variant MethodBind2R<R, P1, P2>::call(Object*, const Variant**, int, Variant::CallError&) [with R = Breuk; P1 = int; P2 = int]':
./core/method_bind.gen.inc:1656:18:   required from here
./core/method_bind.gen.inc:1681:36: error: conversion from 'Breuk' to non-scalar type 'Variant' requested
 1681 |   Variant ret = (instance->*method)(_VC(1), _VC(2));
      |                 ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~
[ 29%] ./core/method_bind.gen.inc: In instantiation of 'void MethodBind2R<R, P1, P2>::ptrcall(Object*, const void**, void*) [with R = Breuk; P1 = int; P2 = int]':
./core/method_bind.gen.inc:1686:15:   required from here
./core/method_bind.gen.inc:1688:22: error: 'encode' is not a member of 'PtrToArg<Breuk>'
 1688 |   PtrToArg<R>::encode(  (instance->*method)(PtrToArg<P1>::convert(p_args[1-1]), PtrToArg<P2>::convert(p_args[2-1])) ,r_ret)  ;
      |   ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[ 29%] ./core/method_bind.gen.inc: In instantiation of 'Variant::Type MethodBind2R<R, P1, P2>::_get_argument_type(int) const [with R = Breuk; P1 = int; P2 = int]':
./core/method_bind.gen.inc:1625:69:   required from 'Variant::Type MethodBind2R<R, P1, P2>::_gen_argument_type(int) const [with R = Breuk; P1 = int; P2 = int]'
./core/method_bind.gen.inc:1625:24:   required from here
./core/method_bind.gen.inc:1637:61: error: incomplete type 'GetTypeInfo<Breuk, void>' used in nested name specifier
 1637 |   if (p_argument==-1) return (Variant::Type)GetTypeInfo<R>::VARIANT_TYPE;
      |                                                             ^~~~~~~~~~~~

The error in image form: foutmeldingGodotC++module1 foutmeldingGodotC++module2

The piece of code that causes this error. maak dezeverbindinggeeftdefout

The module that causes this error:breuk.zip

Steps to reproduce

  1. Follow the steps on https://docs.godotengine.org/en/stable/development/cpp/custom_modules_in_cpp.html to create your own module. Alternatively, just take breuk.zip
  2. Now, in the class that you created, create a function that returns a class instance. This could be as in my example: Breuk Breuk::maak(int x, int y) { return Breuk(x, y); }
  3. Now bind this class in the _bind_methods() function of the class using ClassDB::bind_method. In my example: ClassDB::bind_method(D_METHOD("maak", "x", "y"), &Breuk::maak);

Now go to the main folder of the cloned repository of Godot and run scons -j8 platform=x11 to compile the project.

You will get a compilation error. This compilation error goes away when outcommenting the binding, or when modifying the bound function in such a way that it returns one of the default types (integer, float, bool, string, char etcetera) rather than return a class instance.

Minimal reproduction project

This error is not occurring when Godot is running, but then Godot is compiling. Therefore, I hereby include the module that evokes this compilation error: breuk.zip

gotnospirit commented 1 year ago

I never created a module before, so I may be wrong, but I think you have to return Ref<Beurk>

Ref<Breuk> Breuk::maak(int x, int y) {
    Ref<Breuk> b;
    b.instantiate();
    b->a = x;
    b->b = y;
    return b;
} // returns a class instance

this compiles without problem.

I took this as an example: https://github.com/godotengine/godot/blob/13d99d1676a72ffa529ffb7cee7ce97582fb42f1/scene/main/scene_tree.cpp#L1857-L1870

Now, I don't know what this module is supposed to do, but I would suggest :

markwiering commented 1 year ago

Thank you, @gotnospirit. Your implementation worked, though I had to change b.instantiate(); into b.instance(); to make it work.

This class is about fractions. I also have a class with Xs and a formula class (where the formula class contains a vector of Xs). I plan to port them all to GDscript, because I am working on an educative cat game that teaches the children (ranging from 12 to 18 years old) mathematics. On each level switch, you are prompted to a screen resembling a Commodore64 (since the cat carries a Commodore64 with him) where you need to solve some mathematical equations in the forms of several multiple choice questions.

I have all those questions implemented in C++, but now I need to port them to GDscript. I am trying to accomplish that with C++ modules, such that I can create a instance of each of this class (fraction, Xs and formula) in GDscript.

But now I hope that I can also port the operator overloaders to GDscript, because if that is not possible, then I need a different approach. Then I need to make bounded C++ functions that generate the question and the correct answer by themselves. This will make the mathematical less flexible (having to recompile the entire engine every single time I want to adjust the difficulty of a question), but it is possible nonetheless in case I cannot bind the operator overloaders to GDscript.

Right now, I am going to rewrite the class functions to make it such that they return Ref<Breuk> instead of Breuk. :-)

gotnospirit commented 1 year ago

I was just trying to solve the compile problem but, before putting Ref<> everywhere, maybe you could have a look to classes like core\math\vector2 Good luck :)

markwiering commented 1 year ago

I will have a look at core/math/vector2, @gotnospirit ! Thank you for the suggestion! :smile: