我对 Luabind 包装器如何在没有 lua_State *L
的情况下传递函数感兴趣。并且不使用 Lua 堆栈。
Luabind 如何:
我不是想创建另一个像 Luabind 这样的绑定(bind)到其他库。我只是想知道他们是怎么做到的。只是一个好奇的人。
最佳答案
好问题。我对 luabind 的工作方式有一些模糊的概念,但我没有足够的知识来完整准确地回答。借助 IDE 和调试器,我开始剖析以下非常简单的部分:
struct C
{
int i;
int f(int x, const char* s)
};
lua_State* L = luaL_newstate();
open(L);
module(L)
[
class_<C>("C")
.def_readwrite("index", &C::i)
.def("f", &C::f)
];
首先要注意的是
L
大量传递给 luabind,调用 open
在 Lua 状态中创建一些全局变量:__luabind_classes
userdata 类型和两个函数 class
和 property
. Luabind 似乎没有使用全局变量——它需要的一切都保存在 lua 环境中。现在我们到达
module(L)[...]
.原始代码是最好的解释,这里首先是module
:inline module_ module(lua_State* L, char const* name = 0)
{
return module_(L, name);
}
很简单,这里是
module_
:class LUABIND_API module_
{
public:
module_(lua_State* L_, char const* name);
void operator[](scope s);
private:
lua_State* m_state;
char const* m_name;
};
所以我们的小程序所做的是在
module_
上调用 operator []。具有一些定义的类(即 scope
参数),但 module_
类知道在哪个 Lua 状态下运行。 scope
类也很有趣(有些部分被省略了,有些部分稍微简化了):struct LUABIND_API scope
{
//...
explicit scope(detail::registration* reg);
scope& operator,(scope s);
void register_(lua_State* L) const;
private:
detail::registration* m_chain;
};
scope
正在构建 detail::registration
的链表节点,该列表来自使用 operator,
.所以当一个人做module(L) [class_<...>..., class_<...>...]
, class_
继承自 scope
用 detail::registration
初始化它的基数实例,然后是 scope
的逗号运算符建立一个所有注册的链表,传递给 module_::operator[]
调用 scope::register_
依次枚举链并调用 register_
所有这些detail::registration
对象。 lua_State
总是传递给 register_
.呸。现在让我们看看当一个人这样做时会发生什么
class_<C>("C").def("f", &C::f)
.这构造了 class_<C>
的实例detail::registration
中的某个名称成员(member) class_
.调用class_::def
方法写入 reg 结构等等,但这里有一个非常有趣的行,位于 def
的调用链中。 : object fn = make_function(
L, f, deduce_signature(f, (Class*)0), policies);
哦,
deduce_signature
,我真的很想看看。现在我想取消它,但它的工作方式是这样的:通过由 boost ( BOOST_PP_ITERATE
和其他一些实用程序) 辅助的暗预处理器巫术,为 1 和 LUABIND_MAX_ARITY 之间的每个 N 生成以下内容:template <class R, class T, class A1, classA2, ..., classAN>
boost::mpl::vectorN_PLUS_2<R, T, A1, A2, ..., AN> // type of return value
deduce_signature(R(T::*)(A1, A2, ..., AN))
{
return boost::mpl::vectorN_PLUS_2<R, T, A1, A2, ..., AN>()
}
同样,为 1 和 LUABIND_MAX_ARITY 之间的所有 N 生成这样的函数,默认情况下为 10。有几个重载来处理 const 方法、虚拟包装器和自由函数等,这意味着大约有 50
deduce_signature
在预处理器之后和编译开始之前最终出现在您的源代码中的函数。从那里,编译器的工作就是选择正确的 deduce_signature
传递给 def
的函数重载这将返回正确的 boost::mpl::vectorX
类型。从那里 make_function
可以做任何事情——它有一个参数类型的 [compile time] 列表,并通过更多的模板魔术来计算这些参数类型,并与 Lua 值相互转换等等。这就是我要停下来的地方。调查基于 Luabind 0.8.1。随意浏览/调试 Luabind 的代码以获得更多答案 - 这需要一些时间,但在你习惯了这种风格后并不难 :) 祝你好运。
TL;DR: 魔法……黑魔法
关于function - Luabind 是如何工作的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6114765/