我已经设法实现并测试了我的函数包装器实现,但是,界面并不像它应该的那样好:
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调用,我想找到一种更接近手写性能的解决方案。
如果我们将函数作为参数传递,我们显然无法在编译时创建函数绑定。
答案 0 :(得分:3)
对不起戴夫,你做不到。
已经提出了一些建议,以便在模板类型列表中稍后从文字类型中推导出模板类型。最后我查了一下,它不会进入C ++ 1y(又名C ++ 14)。
在语言添加功能之前,宏可以提供帮助:
#define REGFUNC( F ) decltype(F), (F)
register_function< REGFUNC(hello) >( "hello" );
还有人谈到在C ++中添加“lambda to C function”支持(能够接受有状态 lambda,并要求它生成一个将使用该状态调用它的C函数) ,但我不知道这是如何进展的。
答案 1 :(得分:0)
将此问题的年龄添加到标记语言版本中:C ++ 17允许使用占位符声明模板参数。
template < auto &F >
void register_function( const char* name )
{
int (*lf) (lua_State *) = function_wrapper< std::remove_reference_t<decltype(F)>, F >;
register_native_function( lf, name );
}
这对于函数特别有用,因为概念类型“ callable”实际上是许多C ++类型。 (使用参考有助于避免register_function<2>("?!")
之类的愚蠢事物。)