godotengine / godot-cpp

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

Ill formed global functions will generate a Variant template error elsewhere on VS2022 #764

Open jokoon opened 2 years ago

jokoon commented 2 years ago

If you uncomment or comment #define NOWEIRDFUNCS, it will generate this error, or fix that error.

Using branch 3.x, building with scons

the compiler keeps pointing at this offending line, for some reason: https://github.com/godotengine/godot-cpp/blob/3.x/include/core/Variant.hpp#L264

Not that struct/public/private are not an issue, it's a matter of style.

\godot-cpp\include\core\Variant.hpp(264): error C2825: 'T': must be a class or namespace when followed by '::'
\headers-repro.h(15): note: see reference to function template instantiation 'godot::Variant::operator const T(void) const<const char>' being compiled
        with
        [
            T=const char
        ]
\godot-cpp\include\core\Variant.hpp(264): error C2510: 'T': left of '::' must be a class/struct/union
\godot-cpp\include\core\Variant.hpp(264): error C3861: '___get_from_variant': identifier not found

Header

#pragma once

#include <string>
#include <map>
#include <vector>
using namespace std;

#include <Godot.hpp>

typedef godot::Vector2 Vec2;

namespace item_json_loader {

    struct item_holder {
        GODOT_CLASS(item_holder, godot::Reference)

    public:
        item_holder();
        void _init();
        static void _register_methods();
    };

}

class_file.cpp

#include "headers-repro.h"

//#define NOWEIRDFUNCS
#ifdef NOWEIRDFUNCS
map<int, int> to_map_int_int(const godot::Dictionary& dict) {
    map<int, int> ret;
    auto keys = dict.keys();
    //auto values = dict.values();
    for (auto k = 0; k < keys.size(); ++k) {
        auto key = (int)keys[k];
        int val = dict[key];
        ret[key] = val;
    }
    return ret;
}
map<string, int> to_map_str_int(const godot::Dictionary& dict) {
    map<string, int> ret;
    auto keys = dict.keys();

    for (auto k = 0; k < keys.size(); ++k) {
        godot::String gd_key = keys[k];
        //string k2 = (string)key;
        //string std_key(gd_key.alloc_c_string());
        string std_key(gd_key.utf8().get_data());

        int val = (int)dict[gd_key];
        ret[std_key] = val;
    }
    return ret;
}
vector<int> to_vec_int(const godot::Array& ar) {
    vector<int> ret(ar.size());
    for (auto k = 0; k < ar.size(); ++k) {
        ret[k] = ar[k];
    }
    return ret;
}
#else

map<int, int> to_map_int_int(godot::Dictionary& dict) {
    map<int, int> ret;
    for (auto k = 0; k < dict.keys().size(); ++k) {
        auto key = (int)dict.keys()[k];
        auto& val = dict.values()[k];
        ret[key] = val;
    }
    return ret;
}
map<string, int> to_map_str_int(godot::Dictionary& dict) {
    map<string, int> ret;
    for (auto k = 0; k < dict.keys().size(); ++k) {
        auto k2 = (string)dict.keys()[k];
        //auto key = (string)k2;
        auto& val = dict.values()[k];
        ret[k2] = (int)val;
    }
    return ret;
}
vector<int> to_vec_int(godot::Array& ar) {
    vector<int> ret(ar.size());
    for (auto k = 0; k < ar.size(); ++k) {
        ret[k] = ar[k];
    }
    return ret;
}
#endif

namespace item_json_loader {
    item_holder::item_holder() {}
    void item_holder::_init() {}
    void item_holder::_register_methods() {}
}

gdlibrary_repro.cpp


#include "headers-repro.h"

extern "C" void GDN_EXPORT godot_gdnative_init(godot_gdnative_init_options *o) {
    godot::Godot::gdnative_init(o);
}

extern "C" void GDN_EXPORT godot_gdnative_terminate(godot_gdnative_terminate_options *o) {
    godot::Godot::gdnative_terminate(o);
}

extern "C" void GDN_EXPORT godot_nativescript_init(void *handle) {
    godot::Godot::nativescript_init(handle);
    godot::register_class<item_json_loader::item_holder>();
}
jokoon commented 2 years ago

To be honest I can't see the difference between those 2 ifdef