能否通过Sol3将Lua函数赋值给C++函数指针或std::function
这个需求完全可以实现,两种写法中std::function的方案是Sol3原生支持的,裸函数指针无法直接赋值,需要额外包装。
具体实现方式
1. 推荐方案:直接使用std::function存储
Sol3内置了对std::function的自动转换支持,只要你自定义的vec3类型提前在Sol3中完成注册,就可以直接赋值,不需要写额外的包装代码。
示例代码:
#include <sol/sol.hpp> #include <functional> // 假设vec3是你自定义的三维向量类型 struct vec3 { float x, y, z; vec3() : x(0), y(0), z(0) {} vec3(float x, float y, float z) : x(x), y(y), z(z) {} }; int main() { sol::state lua; lua.open_libraries(sol::lib::base); // 必须在获取Lua函数前注册自定义类型,否则Sol3无法完成参数/返回值转换 lua.new_usertype<vec3>("vec3", sol::constructors<vec3(), vec3(float, float, float)>(), "x", &vec3::x, "y", &vec3::y, "z", &vec3::z ); // 加载并执行Lua脚本,保证Idle.animate函数已经在Lua环境中定义 lua.script(R"( Idle = {} function Idle.animate(a, b, c, pos) return vec3(pos.x + a, pos.y + b, pos.z + c) end )"); // 直接赋值即可,Sol3自动完成类型适配 std::function<vec3(float, float, float, vec3)> saved_script = lua["Idle"]["animate"]; // 后续可以随时延迟调用,不需要持有Lua栈或者sol::state的额外引用 vec3 result = saved_script(1.0f, 2.0f, 3.0f, vec3(0,0,0)); return 0; }
注意事项:
- 存储的
std::function生命周期不能超过对应的sol::state实例,否则调用时虚拟机已经销毁,会触发未定义行为 - 如果Lua侧对应函数不存在、签名和
std::function不匹配,赋值或调用时Sol3会抛出sol::error异常,按需做异常捕获即可 - 如果不想使用异常,可以先将Lua函数存为
sol::protected_function,再绑定到std::function,调用时可以手动处理错误
2. 不推荐方案:裸函数指针
你写的裸函数指针直接赋值的写法不可行。原因是Lua函数的执行依赖Lua虚拟机上下文,纯C裸函数指针不携带任何上下文状态,无法直接绑定到Lua侧的函数。
如果一定要用裸函数指针,只能通过全局/静态变量持有Lua状态和函数引用,再写一层静态包装函数:
// 全局持有Lua状态和函数引用,多虚拟机、多函数场景完全无法适配 sol::state* g_lua_ctx = nullptr; sol::reference g_animate_ref = sol::lua_nil; vec3 animate_wrapper(float a, float b, float c, vec3 pos) { return g_animate_ref.as<sol::protected_function>()(a, b, c, pos).get<vec3>(); } // 初始化时手动绑定全局状态 g_lua_ctx = &lua; g_animate_ref = lua["Idle"]["animate"]; // 之后才能拿到可用的裸函数指针 vec3 (*saved_script)(float, float, float, vec3) = animate_wrapper;
这种方案存在明显缺陷:依赖全局状态、无法支持多实例、需要手动管理引用生命周期,除非是老旧接口强制要求传裸函数指针,否则完全不建议使用。
内容的提问来源于stack exchange,提问作者RLim
相关产品推荐
相关产品推荐

