Search code examples
c++vectorgodot

Creating a new array type compatible with `godot::Variant`?


Writing an add-on with GDExtension, I'm looking to return an array of custom types on Godot 4. My first thought was writing a type like godot::Vector<godot::Ref<MyStruct>>, but I discovered that the compiler complains, as this new type is incompatible with godot::Variant.

So, I would like to know how I'm supposed to fulfil the requirements imposed by godot-cpp. Here the compiler error:

➜  scons
scons: Reading SConscript files ...
Auto-detected 12 CPU cores available for build parallelism. Using 11 cores by default. You can override it with the -j argument.
Building for architecture x86_64 on platform linux
scons: done reading SConscript files.
scons: Building targets ...
scons: `godot-cpp/bin/libgodot-cpp.linux.template_debug.x86_64.a' is up to date.
g++ -o godot/hand_ranking_evaluation.os -c -std=c++17 -fPIC -Wwrite-strings -m64 -march=x86-64 -O2 -fPIC -DLINUX_ENABLED -DUNIX_ENABLED -DDEBUG_ENABLED -DDEBUG_METHODS_ENABLED -DNDEBUG -Igodot-cpp/gdextension -Igodot-cpp/include -Igodot-cpp/gen/include -I/nix/store/5hch4vqzwan8ksab4pfpyrbb7wvvv3ad-cxxtest-4.4/include -I/nix/store/7nbh3b6hhjqjs3nfy529g38l85iv46i9-openssl-3.0.11-dev/include -Isrc -Iompeval/omp -Igodot godot/hand_ranking_evaluation.cpp
g++ -o godot/register_types.os -c -std=c++17 -fPIC -Wwrite-strings -m64 -march=x86-64 -O2 -fPIC -DLINUX_ENABLED -DUNIX_ENABLED -DDEBUG_ENABLED -DDEBUG_METHODS_ENABLED -DNDEBUG -Igodot-cpp/gdextension -Igodot-cpp/include -Igodot-cpp/gen/include -I/nix/store/5hch4vqzwan8ksab4pfpyrbb7wvvv3ad-cxxtest-4.4/include -I/nix/store/7nbh3b6hhjqjs3nfy529g38l85iv46i9-openssl-3.0.11-dev/include -Isrc -Iompeval/omp -Igodot godot/register_types.cpp
In file included from godot-cpp/include/godot_cpp/core/class_db.hpp:38,
                 from godot-cpp/gen/include/godot_cpp/classes/ref_counted.hpp:39,
                 from godot/../godot-cpp/include/godot_cpp/classes/ref.hpp:37,
                 from godot/poker.hpp:5,
                 from godot/hand_ranking_evaluation.cpp:1:
godot-cpp/include/godot_cpp/core/method_bind.hpp: In instantiation of 'GDExtensionVariantType godot::MethodBindTR<R, P>::gen_argument_type(int) const [with R = godot::Vector<godot::Ref<HandRankEvaluation> >; P = {}]':
godot-cpp/include/godot_cpp/core/method_bind.hpp:446:33:   required from here
godot-cpp/include/godot_cpp/core/method_bind.hpp:450:71: error: incomplete type 'godot::GetTypeInfo<godot::Vector<godot::Ref<HandRankEvaluation> >, void>' used in nested name specifier
  450 |                         return GDExtensionVariantType(GetTypeInfo<R>::VARIANT_TYPE);
      |                                                                       ^~~~~~~~~~~~
godot-cpp/include/godot_cpp/core/method_bind.hpp: In instantiation of 'godot::PropertyInfo godot::MethodBindTR<R, P>::gen_argument_type_info(int) const [with R = godot::Vector<godot::Ref<HandRankEvaluation> >; P = {}]':
godot-cpp/include/godot_cpp/core/method_bind.hpp:454:23:   required from here
godot-cpp/include/godot_cpp/core/method_bind.hpp:460:62: error: incomplete type 'godot::GetTypeInfo<godot::Vector<godot::Ref<HandRankEvaluation> >, void>' used in nested name specifier
  460 |                         return GetTypeInfo<R>::get_class_info();
      |                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
godot-cpp/include/godot_cpp/core/method_bind.hpp: In instantiation of 'GDExtensionClassMethodArgumentMetadata godot::MethodBindTR<R, P>::get_argument_metadata(int) const [with R = godot::Vector<godot::Ref<HandRankEvaluation> >; P = {}]':
godot-cpp/include/godot_cpp/core/method_bind.hpp:468:49:   required from here
godot-cpp/include/godot_cpp/core/method_bind.hpp:472:48: error: incomplete type 'godot::GetTypeInfo<godot::Vector<godot::Ref<HandRankEvaluation> >, void>' used in nested name specifier
  472 |                         return GetTypeInfo<R>::METADATA;
      |                                                ^~~~~~~~
In file included from godot-cpp/include/godot_cpp/core/method_bind.hpp:34:
godot-cpp/include/godot_cpp/core/binder_common.hpp: In instantiation of 'void godot::call_with_variant_args_ret_helper(T*, R (T::*)(P ...), const Variant**, Variant&, GDExtensionCallError&, IndexSequence<Is ...>) [with T = _gde_UnexistingClass; R = Vector<Ref<HandRankEvaluation> >; P = {}; long unsigned int ...Is = {}]':
godot-cpp/include/godot_cpp/core/binder_common.hpp:381:35:   required from 'void godot::call_with_variant_args_ret_dv(T*, R (T::*)(P ...), const void* const*, int, Variant&, GDExtensionCallError&, const std::vector<Variant>&) [with T = _gde_UnexistingClass; R = Vector<Ref<HandRankEvaluation> >; P = {}; GDExtensionConstVariantPtr = const void*]'
godot-cpp/include/godot_cpp/core/method_bind.hpp:481:32:   required from 'godot::Variant godot::MethodBindTR<R, P>::call(GDExtensionClassInstancePtr, const void* const*, GDExtensionInt, GDExtensionCallError&) const [with R = godot::Vector<godot::Ref<HandRankEvaluation> >; P = {}; GDExtensionClassInstancePtr = void*; GDExtensionConstVariantPtr = const void*; GDExtensionInt = long int]'
godot-cpp/include/godot_cpp/core/method_bind.hpp:476:18:   required from here
godot-cpp/include/godot_cpp/core/binder_common.hpp:261:15: error: no match for 'operator=' (operand types are 'godot::Variant' and 'godot::Vector<godot::Ref<HandRankEvaluation> >')
  261 |         r_ret = (p_instance->*p_method)(VariantCasterAndValidate<P>::cast(p_args, Is, r_error)...);
      |         ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from godot-cpp/include/godot_cpp/variant/typed_array.hpp:35,
                 from godot-cpp/gen/include/godot_cpp/classes/object.hpp:41,
                 from godot/../godot-cpp/include/godot_cpp/classes/ref.hpp:36:
godot-cpp/include/godot_cpp/variant/variant.hpp:252:18: note: candidate: 'godot::Variant& godot::Variant::operator=(const godot::Variant&)'
  252 |         Variant &operator=(const Variant &other);
      |                  ^~~~~~~~
godot-cpp/include/godot_cpp/variant/variant.hpp:252:43: note:   no known conversion for argument 1 from 'godot::Vector<godot::Ref<HandRankEvaluation> >' to 'const godot::Variant&'
  252 |         Variant &operator=(const Variant &other);
      |                            ~~~~~~~~~~~~~~~^~~~~
godot-cpp/include/godot_cpp/variant/variant.hpp:253:18: note: candidate: 'godot::Variant& godot::Variant::operator=(godot::Variant&&)'
  253 |         Variant &operator=(Variant &&other);
      |                  ^~~~~~~~
godot-cpp/include/godot_cpp/variant/variant.hpp:253:38: note:   no known conversion for argument 1 from 'godot::Vector<godot::Ref<HandRankEvaluation> >' to 'godot::Variant&&'
  253 |         Variant &operator=(Variant &&other);
      |                            ~~~~~~~~~~^~~~~
godot-cpp/include/godot_cpp/core/binder_common.hpp: In instantiation of 'void godot::call_with_ptr_args_ret_helper(T*, R (T::*)(P ...), const void* const*, void*, IndexSequence<Is ...>) [with T = _gde_UnexistingClass; R = Vector<Ref<HandRankEvaluation> >; P = {}; long unsigned int ...Is = {}; GDExtensionConstTypePtr = const void*]':
godot-cpp/include/godot_cpp/core/binder_common.hpp:224:43:   required from 'void godot::call_with_ptr_args(T*, R (T::*)(P ...), const void* const*, void*) [with T = _gde_UnexistingClass; R = Vector<Ref<HandRankEvaluation> >; P = {}; GDExtensionConstTypePtr = const void*]'
godot-cpp/include/godot_cpp/core/method_bind.hpp:489:36:   required from 'void godot::MethodBindTR<R, P>::ptrcall(GDExtensionClassInstancePtr, const void* const*, GDExtensionTypePtr) const [with R = godot::Vector<godot::Ref<HandRankEvaluation> >; P = {}; GDExtensionClassInstancePtr = void*; GDExtensionConstTypePtr = const void*; GDExtensionTypePtr = void*]'
godot-cpp/include/godot_cpp/core/method_bind.hpp:485:15:   required from here
godot-cpp/include/godot_cpp/core/binder_common.hpp:204:28: error: 'encode' is not a member of 'godot::PtrToArg<godot::Vector<godot::Ref<HandRankEvaluation> > >'
  204 |         PtrToArg<R>::encode((p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...), r_ret);
      |         ~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
godot-cpp/include/godot_cpp/core/binder_common.hpp: In instantiation of 'void godot::call_get_argument_type_helper(int, int&, GDExtensionVariantType&) [with Q = Vector<Ref<HandRankEvaluation> >]':
godot-cpp/include/godot_cpp/core/binder_common.hpp:440:53:   required from 'GDExtensionVariantType godot::call_get_argument_type(int) [with P = {Vector<Ref<HandRankEvaluation> >}]'
godot-cpp/include/godot_cpp/core/method_bind.hpp:295:39:   required from 'GDExtensionVariantType godot::MethodBindT<P>::gen_argument_type(int) const [with P = {godot::Vector<godot::Ref<HandRankEvaluation> >}]'
godot-cpp/include/godot_cpp/core/method_bind.hpp:293:33:   required from here
godot-cpp/include/godot_cpp/core/binder_common.hpp:429:63: error: incomplete type 'godot::GetTypeInfo<godot::Vector<godot::Ref<HandRankEvaluation> >, void>' used in nested name specifier
  429 |                 type = GDExtensionVariantType(GetTypeInfo<Q>::VARIANT_TYPE);
      |                                                               ^~~~~~~~~~~~
godot-cpp/include/godot_cpp/core/binder_common.hpp: In instantiation of 'void godot::call_get_argument_type_info_helper(int, int&, PropertyInfo&) [with Q = Vector<Ref<HandRankEvaluation> >]':
godot-cpp/include/godot_cpp/core/binder_common.hpp:459:58:   required from 'void godot::call_get_argument_type_info(int, PropertyInfo&) [with P = {Vector<Ref<HandRankEvaluation> >}]'
godot-cpp/include/godot_cpp/core/method_bind.hpp:304:37:   required from 'godot::PropertyInfo godot::MethodBindT<P>::gen_argument_type_info(int) const [with P = {godot::Vector<godot::Ref<HandRankEvaluation> >}]'
godot-cpp/include/godot_cpp/core/method_bind.hpp:301:23:   required from here
godot-cpp/include/godot_cpp/core/binder_common.hpp:449:54: error: incomplete type 'godot::GetTypeInfo<godot::Vector<godot::Ref<HandRankEvaluation> >, void>' used in nested name specifier
  449 |                 info = GetTypeInfo<Q>::get_class_info();
      |                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
godot-cpp/include/godot_cpp/core/binder_common.hpp: In instantiation of 'void godot::call_get_argument_metadata_helper(int, int&, GDExtensionClassMethodArgumentMetadata&) [with Q = Vector<Ref<HandRankEvaluation> >]':
godot-cpp/include/godot_cpp/core/binder_common.hpp:479:57:   required from 'GDExtensionClassMethodArgumentMetadata godot::call_get_argument_metadata(int) [with P = {Vector<Ref<HandRankEvaluation> >}]'
godot-cpp/include/godot_cpp/core/method_bind.hpp:316:42:   required from 'GDExtensionClassMethodArgumentMetadata godot::MethodBindT<P>::get_argument_metadata(int) const [with P = {godot::Vector<godot::Ref<HandRankEvaluation> >}]'
godot-cpp/include/godot_cpp/core/method_bind.hpp:315:49:   required from here
godot-cpp/include/godot_cpp/core/binder_common.hpp:467:38: error: incomplete type 'godot::GetTypeInfo<godot::Vector<godot::Ref<HandRankEvaluation> >, void>' used in nested name specifier
  467 |                 md = GetTypeInfo<Q>::METADATA;
      |                                      ^~~~~~~~
godot-cpp/include/godot_cpp/core/binder_common.hpp: In instantiation of 'void godot::call_with_ptr_args_helper(T*, void (T::*)(P ...), const void* const*, IndexSequence<Is ...>) [with T = _gde_UnexistingClass; P = {Vector<Ref<HandRankEvaluation> >}; long unsigned int ...Is = {0}; GDExtensionConstTypePtr = const void*]':
godot-cpp/include/godot_cpp/core/binder_common.hpp:214:36:   required from 'void godot::call_with_ptr_args(T*, void (T::*)(P ...), const void* const*, void*) [with T = _gde_UnexistingClass; P = {Vector<Ref<HandRankEvaluation> >}; GDExtensionConstTypePtr = const void*]'
godot-cpp/include/godot_cpp/core/method_bind.hpp:331:33:   required from 'void godot::MethodBindT<P>::ptrcall(GDExtensionClassInstancePtr, const void* const*, GDExtensionTypePtr) const [with P = {godot::Vector<godot::Ref<HandRankEvaluation> >}; GDExtensionClassInstancePtr = void*; GDExtensionConstTypePtr = const void*; GDExtensionTypePtr = void*]'
godot-cpp/include/godot_cpp/core/method_bind.hpp:327:15:   required from here
godot-cpp/include/godot_cpp/core/binder_common.hpp:194:53: error: 'convert' is not a member of 'godot::PtrToArg<godot::Vector<godot::Ref<HandRankEvaluation> > >'
  194 |         (p_instance->*p_method)(PtrToArg<P>::convert(p_args[Is])...);
      |                                 ~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
godot-cpp/include/godot_cpp/core/binder_common.hpp: In instantiation of 'static T godot::VariantCasterAndValidate<T>::cast(const godot::Variant**, uint32_t, GDExtensionCallError&) [with T = godot::Vector<godot::Ref<HandRankEvaluation> >; uint32_t = unsigned int]':
godot-cpp/include/godot_cpp/core/binder_common.hpp:237:59:   required from 'void godot::call_with_variant_args_helper(T*, void (T::*)(P ...), const Variant**, GDExtensionCallError&, IndexSequence<Is ...>) [with T = _gde_UnexistingClass; P = {Vector<Ref<HandRankEvaluation> >}; long unsigned int ...Is = {0}]'
godot-cpp/include/godot_cpp/core/binder_common.hpp:311:31:   required from 'void godot::call_with_variant_args_dv(T*, void (T::*)(P ...), const void* const*, int, GDExtensionCallError&, const std::vector<Variant>&) [with T = _gde_UnexistingClass; P = {Vector<Ref<HandRankEvaluation> >}; GDExtensionConstVariantPtr = const void*]'
godot-cpp/include/godot_cpp/core/method_bind.hpp:323:28:   required from 'godot::Variant godot::MethodBindT<P>::call(GDExtensionClassInstancePtr, const void* const*, GDExtensionInt, GDExtensionCallError&) const [with P = {godot::Vector<godot::Ref<HandRankEvaluation> >}; GDExtensionClassInstancePtr = void*; GDExtensionConstVariantPtr = const void*; GDExtensionInt = long int]'
godot-cpp/include/godot_cpp/core/method_bind.hpp:319:18:   required from here
godot-cpp/include/godot_cpp/core/binder_common.hpp:150:89: error: incomplete type 'godot::GetTypeInfo<godot::Vector<godot::Ref<HandRankEvaluation> >, void>' used in nested name specifier
  150 |                 GDExtensionVariantType argtype = GDExtensionVariantType(GetTypeInfo<T>::VARIANT_TYPE);
      |                                                                                         ^~~~~~~~~~~~
scons: *** [godot/hand_ranking_evaluation.os] Error 1
scons: building terminated because of errors.

Solution

  • If you are using a type already registered with the Godot binding API you can use godot::Array or godot::TypedArray<T> (which enforces the type of any added item). For that matter godot::Array already uses a godot::Vector<Variant> under the hood.

    You could implement a custom array container as a godot::RefCounted but that likely wouldn't act as you would expect, and Godot's own types should be powerful enough for most use cases.