ThePhD / sol2

Sol3 (sol2 v3.0) - a C++ <-> Lua API wrapper with advanced features and top notch performance - is here, and it's great! Documentation:
http://sol2.rtfd.io/
MIT License
4.06k stars 492 forks source link

Passing nil as userdata to C++ to reset a variable #1592

Closed diath closed 3 months ago

diath commented 3 months ago

Hi, I have a C++ function that accepts std::shared_ptr<Type> as an argument, I want to also be able to call the function with nil from Lua, to reset the said pointer, however it's not possible because sol expects actual userdata type on the stack, is there a way to work around this without adding a separate function for resetting the pointer?

Example: https://godbolt.org/z/s964fx36e

Rochet2 commented 3 months ago

This would work, so take sol::optional<std::shared_ptr<Widget>> as argument or make a wrapper for the binding if you cant change setActiveWidget.

#include <memory>
#include <limits>

#include <sol/sol.hpp>

struct Widget
{
};

std::shared_ptr<Widget> active;

void setActiveWidget(sol::optional<std::shared_ptr<Widget>> w)
{
    if (w)
        active = *w;
    else
        active.reset();
}

int main(int, char **)
{
    sol::state state;
    state.new_usertype<Widget>("Widget",
        sol::factories([]() {
            return std::make_shared<Widget>();
        })
    );
    state["setActiveWidget"] = &setActiveWidget;

    state.script("setActiveWidget(Widget.new())");
    state.script("setActiveWidget(nil)");

    return 0;
}
diath commented 3 months ago

I can change the API, so that works, just a bit unfortunate that I need to include the sol header in that class now which adds a bit of compile time overhead. Thanks.

Rochet2 commented 3 months ago

You can also just do this instead to avoid the compile overhead but have a wrapper.

state["setActiveWidget"] = [](sol::optional<std::shared_ptr<Widget>> w){ return setActiveWidget(w ? *w : std::shared_ptr<Widget>()); };