我已经设法实现并测试了我的函数包装器实现,但是,接口并没有它应该的那么好:
template < typename F, F* f >
void register_function( const char* name )
{
int (*lf) (lua_State *) = function_wrapper< F, f >;
register_native_function( lf, name );
}
虽然这按预期工作,但使用需要显式模板参数:
register_function< decltype(hello), &hello >( "hello" );
显然第一个参数可以从第一个参数推导出来,所以理想情况下我只想拥有
register_function< &hello >( "hello" );
可能吗?有没有更简洁的方法来做到这一点?
更新:回答问题,为什么参数模板化而不是传递:
许多绑定器(包括 Lua 绑定器,因为这是专门为 Lua 设计的)通过值传递函数:
register_function("hello", &hello);
这确实更具可读性,并且从接口方面更容易实现。但这也意味着函数的地址需要存储在某个地方。
要将函数绑定到 Lua,我们需要它具有以下原型:
int (*lua_CFunction) (lua_State *)
没有传递其他信息,因此这是我们从 Lua 调用绑定函数时获得的条目和信息。
如果绑定是在编译时完成的,我们可以在将从 Lua 执行的代码中提供一个单独的函数(通过模板),从而为我们提供与手写绑定相当的性能,尤其是在编译器优化掉样板代码的情况下。
如果绑定是在运行时完成的,那么我们就不能创建新的函数,并且需要一个全局函数,它以某种方式知道它应该将调用调度到哪个函数。通常,我们根本无法获取信息,但现有的编译时 Lua 绑定器利用 Lua 自定义的每函数用户数据或闭包来存储执行执行所需的附加信息。但是,与手写绑定相比,这对性能有很大影响,因为可能会分配额外的内存和闭包调度。
我在以前的绑定实现中遇到了运行时版本的性能问题(尽管压力很大),最终将压力最大的部分重写为手写绑定,并且考虑到这次我打算做 lua在实时渲染循环中调用,我想找到一个更接近手写性能的解决方案。
如果我们将函数作为参数传递,我们显然无法在编译时创建函数绑定。