2013-05-16 22 views
1

我在使用模板参数创建静态包装函数时遇到了一些麻烦。我不想直接传递给函数的包装函数,因为它需要一个特定的签名int (lua_State *)以便它可以传递到下面的功能:使用特定签名创建C++静态包装函数

lua_pushcfunction(L, function); 

(这是正确的,我要去一个自动生成lua包装。)

我的第一个想法是创建一个带有函数指针的模板函数作为非类型的模板参数。

template <void(* f)(void)> 
int luaCaller(lua_State * _luaState) 
{ 
    f(); 

    return 0; 
} 

到目前为止,这看起来不错。此函数具有适当的签名,并调用我通过模板参数传入的函数。

&(luaCaller<myFunc>) 

当我尝试在另一个函数中包装它时,出现了我的问题。非类型模板参数必须外部链接,因此下面将失败:

void pushFunction(lua_State * _luaState, void(* _f)(void)) 
{ 
    lua_pushcfunction(_luaState, &(luaCaller<_f>)); 
} 

这是有道理的,因为需要在编译时是已知函数的地址。你不能扔任何指针,并期望编译器知道要创建哪些类。不幸的是,如果我在编译时添加一个函数指针,它仍然会失败。函数指针的值被复制到_a中,因此_a在编译时仍然在技术上不为人知。正因为如此,我希望下面的工作:

void pushFunction(lua_State * _luaState, void(* const _f)(void)) 
{ 
    lua_pushcfunction(_luaState, &(luaCaller<_f>)); 
} 

也许

void pushFunction(lua_State * _luaState, void(* & _f)(void)) 
{ 
    lua_pushcfunction(_luaState, &(luaCaller<_f>)); 
} 

在第一种情况下,由于该值不允许改变,我们知道,如果它是外部它在技术上仍然是外部联系的。在第二种情况下,它被作为参考传入,这意味着它应该有相同的连接,不是?但这些尝试都没有奏效。为什么?不知怎的,是否有可能规避这种情况?我如何干净地自动生成一个调用另一个函数的函数?

+0

仅仅因为一个参数是'const'和你提供一个编译时常量不会使参数成为编译时常数,令人伤心。 –

+0

这对我来说很奇怪。是否因为你可以简单地强制转换为const?想到这一点。 – lowq

+1

是的,这是因为当编译器编译'doCaller'时,它不知道未来会传递给它什么。其他地方可以并且可能通过运行时间变量。编译器绝对没有指示参数是编译时间常量,只有一个指示,即一旦函数开始,您将不会修改该参数。 –

回答

1

const限定符表示您不允许更改某些内容,而不是它是编译时常量。当函数被调用时,在运行时确定_a的初始值;对于* const &a,如果引用的基础对象不是const,则该值甚至可以在运行时通过某种外部方法(如另一个线程)更改。

为了使全模板化的包装工作,你需要给编译器足够的信息来编译每个可能的模板参数的功能,并提供逻辑这些功能之间进行切换。模板系统生成并组织相关功能,但它不是一个动态调度程序。

如果你能函数指针添加到lua_State对象和消除模板参数,这将是一个解决方案。如果使函数指针模板参数doCaller

您的解决方案会工作,但就失去意义了。

+0

我实际上已经完成了你的建议并将函数指针添加到了lua_State中。但是,我很快意识到我需要一种独立于lua_State来存储这些函数的方法,并且在我的实现中它们实际上都是不同的签名。有一个int(lua_State *)列表是存储它们的一种便捷方式。 (我有很多variadic模板;我的例子是一个简化的例子) – lowq

+0

@roadkillguy模板如何知道如何调用它们,如果它们都有不同的签名? – Potatoswatter

+0

确实很聪明。 – lowq

1

您可以使用带有静态luaCaller方法的struct,而不是使用非类型的函数模板方法来绑定要在包装函数中调用的辅助函数。这应该允许您保留将luaCaller传递到lua_pushcfunction所需的功能签名。

因此,举例来说,你可以有一个结构,看起来像下面这样:

template<void (*f) void> 
struct wrapper 
{ 
    static int luaCaller(lua_State * _luaState) 
    { 
     f(); 

     return 0; 
    } 
}; 

template<typename Functor> 
void doCaller(lua_State * _luaState, Functor wrapper) 
{ 
    Functor::luaCaller(_luaState); 
} 

然后调用它:

doCaller(&luaState, wrapper<my_func>()); 
+0

'T'做什么?这里的模板参数从不使用。 – Potatoswatter

+0

是的,那个解决方案不是很好......我想我已经想出了一个更好的解决方案。 – Jason

+0

啊,我明白了,你传递了Functor作为参数,所以你不需要在doCaller中明确指定模板参数。 'doCaller >(luaState)'也可以,是吗? – lowq