Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: Is there a C++ way to query the metatable of a sol::protected_function? #1650

Open
joergbrech opened this issue Nov 21, 2024 · 1 comment

Comments

@joergbrech
Copy link

joergbrech commented Nov 21, 2024

Thanks a lot for this amazing library!

With sol2, you can query the metatable of tables and table proxys using my_table[sol::metatable_key]. Is there any way to query the metatable of a sol::protected_function directly using the sol API? It doesn't implement operator[] and I found no way to convert it to a table or proxy type. A generic function like sol::getmetatable would be cool.

My use case is that I want to attach metadata to my C++ functions like so:

template <typename Table, typename Key, typename T>
void add_metadata(sol::state_view& lua, Table&& t, Key&& key, T&& value)
{
    if (!t[sol::metatable_key].valid()) {
        sol::table func_meta = lua.create_table();
        t[sol::metatable_key] = func_meta;
    }
    t[sol::metatable_key][std::forward<Key>(key)] = std::forward<T>(value);
}

int main()
{
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    auto g = lua.globals();
    lua.set_function("bar", [](){});
    add_metadata(lua, g["bar"], "foo", "baz");
    
    foobar(lua, g["bar"]); // see below

    return 0;
}

Now I want to query this metadata in a context (function body of foobar), where I don't have g["bar"], but rather a sol::protected_function. I managed to retrieve the metatable with sol::state::script and one line of LUA code, but it would be nice to have something in the C++ API (which might boost performance as well?):

template <typename Table, typename Key>
auto get_metadata(sol::state_view& lua, Table&& t, Key&& key)
{
    // This works, but I was hoping for a cleaner solution
    lua["_tmp"] = t;
    lua.script(R"(
        _tmp = getmetatable(_tmp)
    )");
    sol::object ret = lua["_tmp"][std::forward<Key>(key)];
    return ret;
}

void foobar(sol::state_view& lua, sol::protected_function const& f)
{
    // in this context, I don't have access to f as a  proxy or table
    std::cout << get_metadata(lua, f, "foo").as<std::string>() << "\n";
}

Run this on godbolt

@shohnwal
Copy link

shohnwal commented Mar 13, 2025

Does that actually work, can functions have metatables? I just checked source for Lua 5.1, 5.4 and LuaJit and I don't see any fields where functions could store a metatable. Tables on the other hand have clearly commented metatable fields.

When I try to do that with

function ClassA:MyFunc()
   setmetatable(self.MyFunc, { data = "meow!" })
end

I get an error bad argument #1 to 'setmetatable' (table expected, got function)

or does this only work with specific Lua versions? (I'm using LuaJit 2.1)
Or does the TableProxy + C++-template work in some wacky magic way when it comes to attaching/getting a metatable to/from functions?

That being said, being able to attach metadata to functions would be an awesome Lua feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants