Luabind如何运作?

koe*_*oer 6 lua bind function wrapper

我对Luabind包装器如何在lua_State *L没有使用Lua堆栈的情况下传递函数感兴趣.

Luabind怎么样:

  1. 算数函数参数?
  2. 将函数参数链接到Lua堆栈?
  3. 链接这些类

我不是要尝试像Luabind那样创建另一个绑定到其他库.我只是想知道他们是怎么做到的.只是一个好奇的男人.

sbk*_*sbk 13

好问题.我对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)
];
Run Code Online (Sandbox Code Playgroud)

首先要注意的L是传递给luabind很多,调用open在Lua状态下创建一些全局变量:__luabind_classes类型为userdata,两个函数classproperty.Luabind似乎没有使用全局变量 - 它所需要的一切都保存在lua环境中.

现在我们来了module(L)[...].原始代码是最好的解释,首先在这里module:

inline module_ module(lua_State* L, char const* name = 0)
{
    return module_(L, name);
}
Run Code Online (Sandbox Code Playgroud)

很简单,这里是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;
};
Run Code Online (Sandbox Code Playgroud)

所以我们的小程序所做的就是在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;
};
Run Code Online (Sandbox Code Playgroud)

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成员中class_.调用class_::def方法会在reg结构和诸如此类的东西中写入,但这里的调用链中更深层次的一条非常有趣的行def:

            object fn = make_function(
                L, f, deduce_signature(f, (Class*)0), policies);
Run Code Online (Sandbox Code Playgroud)

噢,deduce_signature我真的很想看到.现在我想要看到它,但它的工作方式是:通过boost(BOOST_PP_ITERATE和其他一些实用程序)辅助的暗预处理器巫术,为一个和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>()
     }
Run Code Online (Sandbox Code Playgroud)

同样,为1和LUABIND_MAX_ARITY之间的所有N生成这样的函数,默认情况下为10.有几个重载来处理const方法,虚拟包装器和自由函数等,这意味着大约有50个deduce_signature函数在预处理器之后和编译开始之前最终出现在源代码中.从那里开始,编译器的工作就是deduce_signature为你传递给def它的函数选择正确的重载,并返回正确的boost::mpl::vectorX类型.从那里make_function可以做任何事情 - 它有一个参数类型的[编译时]列表,通过一些模板魔术,这些被计算,转换为Lua值和从Lua值转换,依此类推.

这是我会停下来的地方.调查基于Luabind 0.8.1.随意浏览/调试Luabind的代码以获得更多答案 - 这需要一些时间,但是在你习惯了这种风格之后并没有那么难:)祝你好运.

TL; DR:魔术......黑魔法


Mud*_*Mud 0

我不熟悉luabind,但“包装器”的整个想法是它构建在一些较低级别的抽象之上,并将其封装起来。luabind几乎可以肯定确实在内部使用lua_State