Sol3中如何检测usertype是否存在 实现创建或获取用户类型逻辑
问题根因
Sol3 原生的new_usertype接口默认不会做存在性校验,只要调用就会在Lua环境中覆盖同名的已注册用户类型元表,所以第二次调用时第一次绑定的testFunction1会被直接清空,只剩第二次绑定的testFunction2。
实现方案
Sol3 没有内置同名usertype复用的接口,可以自行实现通用的CreateOrGetUserType辅助函数,逻辑是注册前先检查对应名称的类型是否已经存在,存在则直接返回已有的usertype实例,不存在才走新建逻辑。
辅助函数实现代码:
#include <sol/sol.hpp> #include <string> #include <utility> template<typename T, typename... CtorArgs> sol::usertype<T> CreateOrGetUserType(sol::state& lua, const std::string& type_name, CtorArgs&&... args) { // 从全局表查询同名对象 sol::object existing_type = lua.globals()[type_name]; // 判断是否是已经注册的目标C++类型对应的usertype if (existing_type.valid() && existing_type.is<sol::usertype<T>>()) { return existing_type.as<sol::usertype<T>>(); } // 不存在则新建注册 return lua.new_usertype<T>(type_name, std::forward<CtorArgs>(args)...); }
使用时直接替换原有new_usertype调用即可,完全匹配预期写法:
sol::state _state; void Func1() { auto userType1 = CreateOrGetUserType<Test>(_state, "Test", sol::constructors<Test()>()); userType1["testFunction1"] = &test1; } void Func2() { auto userType2 = CreateOrGetUserType<Test>(_state, "Test", sol::constructors<Test()>()); userType2["testFunction2"] = &test2; } int main() { _state.open_libraries(sol::lib::base); Func1(); Func2(); // 脚本侧可正常调用两个方法 _state.script(R"( local inst = Test.new() inst:testFunction1() inst:testFunction2() )"); return 0; }
注意事项
- 首次注册时传入的构造函数、基类绑定、元方法(比如
__index、__gc)等核心类型配置会永久生效,后续获取已存在usertype时传入的同类配置不会覆盖原有设置,不会产生冲突 - 不管是第几次拿到usertype实例,通过
[]赋值绑定的方法、属性都会追加到类型定义上,不会清除之前绑定的成员 - 如果需要把usertype注册到自定义模块表而非全局环境,只需要把辅助函数中查询
lua.globals()的逻辑替换为查询对应的父表对象即可
内容的提问来源于stack exchange,提问作者Shadow fiend
相关产品推荐
相关产品推荐

