如何在c ++中将成员函数注册到没有lua bind的lua

时间:2015-09-05 18:27:42

标签: c++ lua

我在我的c ++游戏项目中使用lua 5.1,但是当我尝试注册c ++成员函数时,我很难使用lua。 我想在lua中使用我的c ++类成员函数,但是lua_register()函数是第3个 参数只能接受c类型的普通函数指针或静态成员函数的指针。

我听说lua绑定库可以解决这个问题,但我不想使用lua bind。这很好,但对我的项目来说太重了。 是否有任何方法可以在没有任何库的情况下注册c ++成员函数? 我该怎么办呢?

2 个答案:

答案 0 :(得分:9)

我自己也经历过同样的经历。

我知道基本上有两个很好的解决方案。一个是好的,如果成员函数是针对每个lua状态只有一个的类。另一个更灵活,但更复杂,更慢。 (我很想学习这些方法的其他方法/改进!)

我认为lua_bind使用了一些与方法1非常相似的模板,但是使用技巧使实现像方法2一样灵活。我认为其中任何一个都比lua_bind更透明。

方法1

(1)对于要传递给lua的my_class的每个成员函数,它应该lua_State * L并返回int

(2)在初始化lua时,将指针存储到my_class中关联的lua_extraspace

*static_cast<my_class**>(lua_getextraspace(L_)) = &instance;

(3)如果要将成员函数传递给lua,请使用如下模板:

typedef int (my_class::*mem_func)(lua_State * L);

// This template wraps a member function into a C-style "free" function compatible with lua.
template <mem_func func>
int dispatch(lua_State * L) {
    my_class * ptr = *static_cast<my_class**>(lua_getextraspace(L));
    return ((*ptr).*func)(L);
}

然后你注册这样的事情:

const luaL_Reg regs[] = {
    { "callback_1", &dispatch<&my_class::callback_1> },
    { "callback_2", &dispatch<&my_class::callback_2> },
    { "callback_3", &dispatch<&my_class::callback_3> },
    { NULL, NULL }
};
luaL_register(L, regs); 

方法1的好处是它非常简单且非常快,我认为它会比lua bind快。因为get_extraspace除了一个小指针算术之外什么都不做。最有可能的是,一个好的编译器可以优化dispatch模板,以便它所做的函数内联,并且没有开销。

您可能想要更改dispatch模板,以便在额外空间检查空指针,这取决于您的lua状态和my_class的生命周期是如何管理的。

潜在地,您还可以在额外空间中存储更复杂的内容,例如指向几个不同对象的指针,甚至是向量或其他内容(您可以阅读有关如何在其文档中配置lua额外空间的内容)。或者您可以将内容存储在lua注册表中,并且调度函数可以从那里检索它们,但是额外空间更快 - 这取决于您。

方法2

在方法2中,你基本上使用通常的lua技术将C ++对象推送到lua所拥有的lua,但你在对象是C ++ std::function的情况下执行它并重载{{1}元函数使它调用函数。 (如果您不在C ++ 11中,则可以使用_call。)

然后,当你想将c ++成员函数推送到lua时,使用boost::function使它成为一个函数对象。

这种方法的缺点是在lua中,“function”的类型实际上是std::bind,但是因为你可以调用它并且将它作为函数使用它并不重要。如果这对你不利,你可以做的一件事是使用相同的技巧,但之后,创建一个具有函数对象userdata作为upvalue的闭包,并且当调用闭包时,它只是将参数转发给函数对象并返回结果。那么闭包的类型在lua中将是userdata,但它基本上会做同样的事情。

function

答案 1 :(得分:-2)

之前的回答是正确的。

就问题而言,这取决于当您从lua调用类成员时,是否希望lua决定使用的对象,或者您希望将其绑定到固定对象实例的成员。如果它是固定的,那么用std :: bind创建一个函数对象是非常简单的,它保存指向要调用的成员函数的指针,并使用this指针调用它,并用lua注册它。

http://en.cppreference.com/w/cpp/utility/functional/bind

代码看起来像这样:

class C {
   public:
      void blah(lua_State* L);
};

C inst;

lua_pushcclosure(L, std::bind(&C::blah, &inst, std::placeholder::_1), 0);
lua_setglobal(L, "blah");

另外,为了更自然地将C / C ++函数与lua绑定,避免编写包装器,请看一下:

http://inspired-code.blogspot.com.au/p/automagical-language-bindings-using-c.html