2012-04-10 96 views
0

我正在尝试编写一个类,该类提取从Lua函数调用(Lua脚本调用已注册的C函数)传递的参数,并将它们传递给已注册方法(IDelegate在我的代码片段),所以我可以执行它并返回值。使用可变参数模板从Lua函数回调(C api)提取参数

假设我寄存器从游戏键盘类下面的方法: long int GameBoard::testFunct(long int);“GB:testFunction”的Lua下用下面的代码:

luaL_newmetatable(mState, "GameBoard"); 
lua_pushstring(mState, "__index"); 
lua_pushvalue(mState, -2); 
lua_settable(mState, -3); 

lua_pushstring(mState,"testFunction"); 
hbt::IDelegate<I32,I32>* ideleg = new MethodDelegatePtr<GameBoard,I32,I32>(NULL, &GameBoard::testFunct); // will be deleted later 
lua_pushlightuserdata (mState, (IDelegate<I32,I32>*)ideleg); 
lua_pushcclosure(mState, LuaCall<I32,GameBoard,I32>::LuaCallback,1); 
lua_settable(mState,-3); 

IDelegate & MethodDelegatePtr用于注册方法,函数和函数,所以我可以稍后给他们打电话

然后LuaCall<I32,GameBoard,I32>::LuaCallback将被称为(以Lua堆栈为参数)当我将在Lua脚本中写入GB:testFunction(17);,然后注册的方法将被触发并返回等待的值。

它的工作原理如果我注册并调用一个没有任何参数的方法。 但如果等待为long int GameBoard::testFunct(long int);任何参数做的话,我已经得到了以下错误......

In static member function static Tr tUnpackLuaArgs<0u>::unpack(IDelegate*, lua_State*, ArgsValue ...) [with C = GameBoard, Tr = int, Args = {long int}, ArgsValue = {std::basic_string}, lua_State = lua_State]’:

instantiated from ‘static Tr tUnpackLuaArgs::unpack(IDelegate*, lua_State*, ArgsValue ...) [with C = GameBoard, Tr = int, Args = {long int}, ArgsValue = {}, unsigned int i = 1u, lua_State = lua_State]’

instantiated from ‘static int LuaCall::LuaCallback(lua_State*) [with C = GameBoard, Args = {long int}, lua_State = lua_State]’

error: no match for call to ‘(MethodDelegatePtr) (std::basic_string&)’

note: no known conversion for argument 1 from ‘std::basic_string’ to ‘long int&’


In static member function ‘static Tr tUnpackLuaArgs<0u>::unpack(IDelegate*, lua_State*, ArgsValue ...) [with C = GameBoard, Tr = int, Args = {long int}, ArgsValue = {bool}, lua_State = lua_State]’:

instantiated from ‘static Tr tUnpackLuaArgs::unpack(IDelegate*, lua_State*, ArgsValue ...) [with C = GameBoard, Tr = int, Args = {long int}, ArgsValue = {}, unsigned int i = 1u, lua_State = lua_State]’

instantiated from ‘static int LuaCall::LuaCallback(lua_State*) [with C = GameBoard, Args = {long int}, lua_State = lua_State]’

error: no match for call to ‘(MethodDelegatePtr) (bool&)’

note: no known conversion for argument 1 from ‘bool’ to ‘long int&’

我找不到为什么ArgsValue试图通过一个std::basic_string<char>或当我注册的方法bool等待long int ...它应该通过long int

这里是我写的类来提取来自Lua脚本函数调用的参数。

template< unsigned int i > 
class tUnpackLuaArgs 
{ 

    public: 
     template< class C, class Tr, class... Args, class... ArgsValue > 
     static Tr unpack(IDelegate<C,Tr,Args...>* ideleg, lua_State *L, ArgsValue... argsVal) 
     { 
      int t = lua_type(L, i+1); 

      if(t == LUA_TNUMBER) 
      { 
       I32 tmpUint = lua_tonumber(L, i+1); 
       return tUnpackLuaArgs< i-1 >::unpack(ideleg, L, argsVal..., tmpUint); 
      } 
      else if(t == LUA_TSTRING) 
      { 
       std::string tmpStr = lua_tostring(L, i+1); 
       return tUnpackLuaArgs< i-1 >::unpack(ideleg, L, argsVal..., tmpStr); 
      } 
      else if(t == LUA_TBOOLEAN) 
      { 
       bool tmpBool = lua_toboolean(L, i+1); 
       return tUnpackLuaArgs< i-1 >::unpack(ideleg, L, argsVal..., tmpBool); 
      } 
      //etc. 
     } 
}; 


template<> 
class tUnpackLuaArgs<0> 
{ 
public: 
    template< class C, class Tr, class... Args, class... ArgsValue > 
    static Tr unpack(IDelegate<C,Tr,Args...>* ideleg, lua_State *L, ArgsValue... argsVal) 
    { 
     //-- Execute the registered method using the LUA arguments 
     //-- and returns the returned value 
     return (*ideleg)(argsVal...); 
    } 
}; 

这里是我如何使用它:

// Specialized template returning an integer 
template <class C, class... Args> 
struct LuaCall<int, C, Args...> 
{ 
    static int LuaCallback(lua_State *L) 
    {  
     //-- retrieve method "IDelegate" from Lua stack etc. 
     //-- then call tUnpackLuaArgs with the arguments to push the returned value onto the lua stack 
     lua_pushnumber(L, tUnpackLuaArgs< sizeof...(Args) >::unpack(funcPtr,L)); 
     return 1; 
    } 
}; 

事实上,如果我删除LUA_TSTRINGLUA_TBOOLEAN从的if/else在unpack功能,它编译和工作正常。

回答

0

就这样,如果您的代码包含例如tUnpackLuaArgs<1>::unpack,那么unpack的主体将热切地实例化全部的可能性(因为它们都可能在运行时取决于Lua栈上参数的类型)。

这包括例如tUnpackLuaArgs<0>::apply<C, Tr, Args..., std::string>,这意味着当Args是例如long int由于std::string无法转换为long int const&,因此operator()IDelegate预期。

您并不需要所有这些可能性:您已经知道您的期望(例如您的案例中的long int)。当您想要long int时提取std::string是没有用的。所以相反,你应该尝试从Lua堆栈中提取你期望的内容(如果转换不起作用,可能会出错,直到运行时才会知道)。

+0

需要注意的是,'tUnpackLuaArgs :: unpack'实例化后的实例化数量是N^d的数量级,其中根据您的代码,d似乎至少为3。为了避免这种情况,你会在编译时做得很好。 – 2012-04-10 08:29:56

+0

我仍然不知道如何提取这些参数,但是您的解释很明确,并确认了我被怀疑出现此问题的原因。谢谢。 – Valkea 2012-04-10 17:28:46

+0

@Valkea你可能会感兴趣的[一个解决方案](http://stackoverflow.com/questions/10014713/build-tuple-using-variadic-templates#comment12805453_10014713)使用元组没有递归(它也有用时,当没有元组参与)。请注意,这里不可能使用递归。 – 2012-04-10 17:53:02