godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.06k stars 65 forks source link

Add support for exposing C++ template classes in GDExtension #9721

Open CoderJo-Pro opened 3 weeks ago

CoderJo-Pro commented 3 weeks ago

Describe the project you are working on

A highly performance required game, with a c++ template class:

template <typename T, typename measure_t = std::size_t>
class grid;

Describe the problem or limitation you are having in your project

I had searching through the source code godot, expecting to found export method for godot::Array class, but all in vain.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

I hope godot can provide a way to export template class in c++, and detailed description.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

It supposed to be used as:

template <typename T, typename measure_t = std::size_t>
class grid;
ClassDB::register_class<grid>(); // overload the origin function
ClassDB::register_template_class<grid>(); // or define another function
ClassDB::register_class<grid<int>>(); // or at least can register a specialization of the template class

or using variant:

class Grid : godot::RefCounted, grid<godot::Variant> // may hold a grid object instead of inherit to grid 
{
    // maybe GDCLASS or some bind_methods stuff
}

ClassDB::register_template_class<Grid>();
# in GDScript
var my_grid: Grid[int]

so two possible implementation, one is to register the type without giving template arguments (I'm doubting myself when I worte this), and the other is to export a derived class which inherits to godot::RefCounted and grid<godot::Variant> (which means it's a godot class), and do some trick in gdscript to make it usage just like it is a template class.

If this enhancement will not be used often, can it be worked around with a few lines of script?

no, it is about gdscript's language binding, which I supposed to be a complicated stuff.

Is there a reason why this should be core and not an add-on in the asset library?

It's about the engine itself, it's highly integrated within the engine, it's part of the engine.

dalexeev commented 3 weeks ago

Is it even possible? C++ templates are an element of generic programming. Each template describes a whole family of types/functions. When substituting specific template parameters, different code is generated. This proposal is probably impossible even for GDExtension, not to mention GDScript.

This is why we have several hardcoded Packed*Array types, and why typed arrays still use Variant under the hood. I think that if we ever add generics to the Godot API type system (like WeakRef[T] and PackedScene[T]) then they will also use the narrowest appropriate base type under the hood (Variant, Object, Node), and restrictions will be imposed only by the GDScript static analyzer and runtime checks.

AThousandShips commented 3 weeks ago

Related:

CoderJo-Pro commented 2 weeks ago

I wonder how the gdscript binding works. It seems to be a interpretive language, I guess. I am thinking about we can make a ClassDB::register_template_class that auto generate a fake template class (maybe use a macro) using variant for the type, so it'll use this fake template in debugging; and generates a real template class on building the project.

and for the

template <typename T, typename measure_t = std::size_t>
class grid;
ClassDB::register_class<grid>();

there is a way to do this:

template <template<typename> typename T>
ClassDB::register_class()
{
    // do something, like "T<godot::Variant>"
}

You should really explain some mechanics of binding between gdscript and the c++ core, it really helps (avoid seeking through the source code...)

Spartan322 commented 2 weeks ago

Templates don't exist at runtime, (they don't even really exist throughout most of the compile time either) GDScript only exists at runtime and can only have runtime provided information, Templates don't even exist in the compiler unless you instantiate them and the machine code can't know anything about them, so I'm don't see how this could ever be accomplished in C++. Like

template<typename T>
struct Foo { T val };

template class Foo<int>;

just becomes

struct Foo_i { int val; }; // the name of Foo is likely to a bit more mangled by every compiler, but this is basically what compiler does when it sees a used template, unused templates literally don't exist

before the compiler even really gets its hands on much of anything.