我正在编写一个通用函数包装器,它可以将任何函数包装到具有该形式的lua样式调用中
int lua_function(lua_State*L)
我希望包装函数是即时生成的,所以我想将函数作为模板参数传递.如果你知道参数的数量(例如2),这是微不足道的:
template <typename R, typename Arg1, typename Arg2, R F(Arg1, Args)>
struct wrapper
Run Code Online (Sandbox Code Playgroud)
但是,我不知道这个数字,所以我请求variadic模板参数求助
// This won't work
template <typename R, typename... Args, R F(Args...)>
struct wrapper
Run Code Online (Sandbox Code Playgroud)
上面的内容不会编译,因为variadic参数必须是最后一个.所以我使用两个级别的模板,外部模板捕获类型,内部模板捕获函数:
template <typename R, typename... Args>
struct func_type<R(Args...)>
{
// Inner function wrapper take the function pointer as a template argument
template <R F(Args...)>
struct func
{
static int call( lua_State *L )
{
// extract arguments from L
F(/*arguments*/);
return 1;
}
};
};
Run Code Online (Sandbox Code Playgroud)
这是有效的,除了包装像这样的函数
double sin(double d) {}
Run Code Online (Sandbox Code Playgroud)
用户必须写
func_type<decltype(sin)>::func<sin>::apply
Run Code Online (Sandbox Code Playgroud)
这很乏味.问题是:有没有更好的,用户友好的方式来做到这一点?(我不能用函数模板来包装整个东西,因为函数参数不能用作模板参数.)
类似的事情std::function并std::result_of使用以下技术来做你想要的变量模板:
template<typename Signature>
struct wrapper; // no base template
template<typename Ret, typename... Args>
struct wrapper<Ret(Args...)> {
// instantiated for any function type
};
Run Code Online (Sandbox Code Playgroud)
你可以扩展上面的内容来添加一个非类型的Ret(&P)(Args...)模板参数(指向功能工作的指针),但你仍然需要decltype在用户级别,即wrapper<decltype(sin), sin>::apply.可以说,如果您决定使用宏来删除重复,那么它将是预处理器的合法使用.
template<typename Sig, Sig& S>
struct wrapper;
template<typename Ret, typename... Args, Ret(&P)(Args...)>
struct wrapper<Ret(Args...), P> {
int
static apply(lua_State*)
{
// pop arguments
// Ret result = P(args...);
// push result & return
return 1;
}
};
// &wrapper<decltype(sin), sin>::apply is your Lua-style wrapper function.
Run Code Online (Sandbox Code Playgroud)
以上编译与ideone的 gcc-4.5 .运行应用程序(可变地)弹出参数,祝你好运(如果你打开一个关于那个的问题,请给我留言).你考虑过使用Luabind吗?