sol2
sol2 copied to clipboard
const correctness of C++ object passed to sol::protected_function
C++ arguments of sol::protected_function looses const-ness. The non-const functions of the C++ class can be called from the lua function.
Minimal reproducible example
class MyClass {
public:
void modify() {
// Modify the object
std::cout << "modify" << std::endl;
}
void inspect() const {
// Inspect the object without modifying it
std::cout << "inspect" << std::endl;
}
};
template <typename Data>
void run(sol::protected_function& view_fnc, const Data& data){
sol::protected_function_result result = view_fnc(data);
}
int main(){
sol::state lua;
lua.open_libraries(sol::lib::base, sol::lib::string, sol::lib::math, sol::lib::utf8);
lua.new_usertype<MyClass>("MyClass",
"modify", &MyClass::modify,
"inspect", &MyClass::inspect
);
static char buffer[] = R"TEMPLATE(
return function(obj)
obj:inspect()
print("inspect called")
obj:modify()
print("modify called")
return "hello"
end
)TEMPLATE";
sol::load_result load_result = lua.load_buffer(buffer, strlen(buffer));
sol::protected_function view = load_result.get<sol::protected_function>();
sol::protected_function_result view_result = view();
sol::protected_function view_fnc = view_result;
MyClass data;
run(view_fnc, data);
return 0;
}
Compiler:
$ /usr/bin/c++ --version c++ (GCC) 14.1.1 20240522
Workaround
There can be many workarounds. The two I am interested in are
Workaround 1
Make two lua bindings for same C++ class MyClass lets call one LMyClass and the other CLMyClass. The CLMyClass will not expose bind any non-const member functions. It will bind the mutable member variables a const properties using sol::readonly.
But the problem with this approach is How will I decide when it should use CLMyClass instead of LMyClass?
Workaround 2
I am trying to workaround it in a different way.
template <typename Class, bool Const>
struct type: public Class{
static constexpr bool is_const = Const;
};
Then provide make two lua user types for type<X, true> and type<X, false> . The problem with this approach is, if class X has a member variable of type std::vector<Y> it has to be transformed to std::vector<type<Y, Const>> which is very difficult to do automatically without any usercode.