Working with TypedArray in C++

Godot Version

4.2

Question

Hi,
In C++ I create a class:

class A: public Node {
	GDCLASS(A, Node)
public
    TypedArray<B> b;

B class:

class B: public  Resource {
	GDCLASS(B, Resource)
public:
	enum Type {
		NONE = 0,
		TEST= 1,
	};
	B::Type type;

now I want to do the following:

for (int i=0; i < b.size(); i++) {
	if (b[I].type == B::Type::TEST) {
		// Do Something
	}
}

but I get an error:
class "godot::Variant" has no member "type"C/C++(135)
any solution?

TypedArray<T>::operator[], which is inherited from Array, is actually returning a Variant.

You could use Variant::get() for getting a property (of course only if you’ve registered that property), or cast it before using it, this could be the most useful way.

can you give me an example?

for (int i=0; i < b.size(); i++) {
	B item = static_cast<B>(b[i]);
	if (b[i].type == B::Type::TEST) {
		// Do Something
	}
}

Still the error:
no suitable user-defined conversion from "godot::Variant" to "godot::B" existsC/C++(312)

I just remembered that we should use Ref<B> instead of B because all RefCounted objects should be wrapped with Ref<T>. I realized this when I found out that Resource doesn’t have a copy/move constructor/operator, and I noticed that Sprite2D contains a Ref<Texture2D> instead of a non-wrapped one. Try using TypedArray<Ref<B>>, and use b[i]->type or store it in a variable first.

operator -> or ->* applied to "godot::Variant" instead of to a pointer typeC/C++(3364)
Edit:
Ref<B>new_b = b[i]
solve the problem

1 Like

So storing b[i] into Ref<b> first does implicitly cast it correctly

Did you modify it to inherit from Ref<Resource>?

No, change it?

No, don’t do that. What did you modify before the error?

I was writing my methods
this error only happens if I want to compile: scons -j2

I just attempted to run this

TypedArray<Image> images;
# Apending a bunch of Image resources...
images.append(Image::create(grid_size.x, grid_size.y, false, Image::Format::FORMAT_RGBAF));
images.append(Image::create(grid_size.x, grid_size.y, false, Image::Format::FORMAT_RGBAF));
images.append(Image::create(grid_size.x, grid_size.y, false, Image::Format::FORMAT_RGBAF));
for (size_t i = 0; i < images.size(); i++)
{
    Ref<Image> image = images[i];
}

So this should work

TypedArray<B> b;
for (size_t i = 0; i < b.size(); i++)
{
    Ref<B> item = b[i];
    if (item.type == B::Type::TEST)
    {
        // Do Something
    }
}

I looked at the code and found that the Ref has an implicit constructor.

Ref(T *p_reference);

And the Variant has an implicit operator.

operator Object *() const;

This explains everything we’ve been doing.

I think I understand what the problem is
Let me test it

TypedArray<B> b;
for (size_t i = 0; i < b.size(); i++)
{
    Ref<B> item = b[i];
    if (item.type == B::Type::TEST)
    {
        test(item);
    }
}

void test(B new_b) {
    //Do something with new_b
}

how to pass the item to the method?
no suitable user-defined conversion from "godot::Ref<godot::B>" to "godot::B" existsC/C++(312)

I came up with a simple conclusion: use raw resource type when stored in arrays, but use Ref as a wrapper when passing as a reference. So define it as void test(Ref<B> new_b); since this is passing the reference.

If I do this, will this work?

gdscript:
var b = B.new()

A.test(b)

This should do, I’ve looked upon sprite_2d.h, and here is the declaration:

Ref<Texture2D> texture;
void set_texture(const Ref<Texture2D> &p_texture);
Ref<Texture2D> get_texture() const;

And we know we’re always using MySprite.texture = some_texture_resource.

so TypedArray<B> bs or TypedArray<Ref<B>> bs?