sol2
sol2 copied to clipboard
Usertype inheritance seems to need open_libraries(sol::lib:base)
I was trying to get inheritance to work on usertypes and bumped into this weird behavior when playing with the example from the documentation:
When you forget to open the sol::lib::base library, the dependency resolution stops working. As the documentation does not include the library import, it seems broken?
#include <sol/sol.hpp>
struct A {
int a = 10;
virtual int call() { return 0; }
virtual ~A(){}
};
struct B : A {
int b = 11;
virtual int call() override { return 20; }
};
int main (int, char*[]) {
sol::state lua;
lua.open_libraries(sol::lib::base); // remove this and it breaks!
lua.new_usertype<B>( "A",
"call", &A::call
);
lua.new_usertype<B>( "B",
"call", &B::call,
sol::base_classes, sol::bases<A>()
);
lua["my_a"] = A{};
lua["my_b"] = B{};
sol::object b_out = lua["my_b"];
std::cout << "A is A: " << lua.get<std::optional<A>>("my_a").has_value() << std::endl;
std::cout << "A is B: " << lua.get<std::optional<B>>("my_a").has_value() << std::endl;
std::cout << "B is A: " << lua.get<std::optional<A>>("my_b").has_value() << std::endl;
std::cout << "B is B: " << lua.get<std::optional<B>>("my_b").has_value() << std::endl;
return 0;
}
Expected output is
A is A: 1
A is B: 0
B is A: 1
B is B: 1
But when I remove the library input I get:
A is A: 1
A is B: 0
B is A: 0
B is B: 1
In my production code it fails in spite of having sol::lib::base opened. But that one uses templated usertypes ...
Ah now it is a typo in the example code from the documentation (and that typo made it via copy-paste to the above code):
In the first usertype declaration, the template parameter is B, while it should be A. When fixing the typo it works:
Also, reading the shared ptr inheritance example, I would expect this code to work:
#include <sol/sol.hpp>
struct A {
int a = 10;
virtual int call() { return 0; }
virtual ~A(){}
};
struct B : A {
int b = 11;
virtual int call() override { return 20; }
};
int main (int, char*[]) {
sol::state lua;
lua.open_libraries(sol::lib::base); // If it's here or not, makes no difference
lua.new_usertype<A>( "A",
"call", &A::call
);
lua.new_usertype<B>( "B",
"call", &B::call,
sol::base_classes, sol::bases<A>()
);
lua["my_a"] = A{};
lua["my_b"] = B{};
std::cout << "A is A: " << lua.get<std::optional<std::shared_ptr<A>>>("my_a").has_value() << std::endl;
std::cout << "A is B: " << lua.get<std::optional<std::shared_ptr<B>>>("my_a").has_value() << std::endl;
std::cout << "B is A: " << lua.get<std::optional<std::shared_ptr<A>>>("my_b").has_value() << std::endl;
std::cout << "B is B: " << lua.get<std::optional<std::shared_ptr<B>>>("my_b").has_value() << std::endl;
return 0;
}
godbolt but the output is just
A is A: 0
A is B: 0
B is A: 0
B is B: 0
Ok this works with the changes:
- I use std::make_shared to create the objects
- The undocumented macros SOL_BASE_CLASSES/SOL_DERIVED_CLASSES are used to define the inheritance structure
#include <sol/sol.hpp>
struct A {
int a = 10;
virtual int call() { return 0; }
virtual ~A(){}
};
struct B : A {
int b = 11;
virtual int call() override { return 20; }
};
SOL_BASE_CLASSES(B, A);
SOL_DERIVED_CLASSES(A, B);
int main (int, char*[]) {
sol::state lua;
lua.open_libraries(sol::lib::base); // If it's here or not, makes no difference
lua.new_usertype<A>( "A",
"call", &A::call
);
lua.new_usertype<B>( "B",
"call", &B::call
);
lua["my_a"] = std::make_shared<A>();
lua["my_b"] = std::make_shared<B>();
std::cout << "A is A: " << lua.get<std::optional<std::shared_ptr<A>>>("my_a").has_value() << std::endl;
std::cout << "A is B: " << lua.get<std::optional<std::shared_ptr<B>>>("my_a").has_value() << std::endl;
std::cout << "B is A: " << lua.get<std::optional<std::shared_ptr<A>>>("my_b").has_value() << std::endl;
std::cout << "B is B: " << lua.get<std::optional<std::shared_ptr<B>>>("my_b").has_value() << std::endl;
return 0;
}