首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Luabind怎么工作?

Luabind怎么工作?
EN

Stack Overflow用户
提问于 2011-05-24 17:59:12
回答 4查看 1.7K关注 0票数 6

我感兴趣的是Luabind包装器如何能够在没有lua_State *L的情况下传递函数而不使用Lua堆栈。

Luabind如何:

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

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

EN

回答 4

Stack Overflow用户

发布于 2011-05-26 16:15:49

问得好。我对luabind是如何做的有一些模糊的想法,但我不知道如何充分准确地回答问题。使用IDE和调试器,我开始剖析以下非常简单的部分:

代码语言:javascript
复制
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状态下创建了几个全局:类型为userdata的__luabind_classes和两个函数classproperty。Luabind似乎没有使用全局变量-它所需要的一切都保存在lua环境中。

现在我们到了module(L)[...]。最初的代码是最好的解释,首先是module

代码语言:javascript
复制
inline module_ module(lua_State* L, char const* name = 0)
{
    return module_(L, name);
}

很简单,这里是module_

代码语言:javascript
复制
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_类上调用运算符[],其中包含一些定义(这是scope参数),但是module_类知道在哪种Lua状态下操作。scope类也很有趣(有些部分省略了,有些部分稍微简化了一些):

代码语言:javascript
复制
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_<...>...]时,继承自scopeclass_使用detail::registration实例初始化其基础,然后scope的逗号运算符构建所有注册的链接列表,这将传递给module_::operator[],后者调用scope::register_,后者将枚举该链并对所有detail::registration对象调用register_lua_State总是传递给register_

呼。现在,让我们看看当一个人做class_<C>("C").def("f", &C::f)时会发生什么。这将使用特定的名称构造class_<C>的一个实例,该名称位于class_中的detail::registration成员中。调用class_::def方法会写入reg结构和诸如此类的内容,但是在def调用链中有一条非常有趣的行

代码语言:javascript
复制
            object fn = make_function(
                L, f, deduce_signature(f, (Class*)0), policies);

哦,deduce_signature,我真的很想看看。现在我想取消它,但是它的工作方式是这样的:通过由boost (BOOST_PP_ITERATE和其他一些实用程序)辅助的暗预处理器魔法,为1和LUABIND_MAX_ARITY之间的每个N生成以下内容:

代码语言:javascript
复制
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可以做任何事情-它有一个参数类型的编译时间列表,并且通过一些更多的模板魔术,这些是计数,转换到和从Lua值等等。

这就是我要停的地方。调查依据是Luabind 0.8.1。可以随意浏览/调试Luabind的代码以获得更多的答案--这需要一些时间,但在您习惯了这种风格之后,这并不难:)祝您好运。

TL博士:魔术..。黑魔法

票数 13
EN

Stack Overflow用户

发布于 2011-05-25 13:12:51

luabind为C所接受的熟悉的int luafunction(lua_State* L)原型提供了模板包装函数。本质上,lua_CFunction是为您创建的。要调用的实际C或C++函数可以存储为包装器的上值。对于C++成员函数,可以从第一个参数中提取this指针。

使用upvalue包装C函数的示例代码:

代码语言:javascript
复制
template<typename R, typename T1>
int arg1wrapper(lua_State* L)
{
    typedef R (*F)(T1);
    F func = (F)lua_touserdata(L, lua_upvalueindex(1));
    R retValue = func(luaToC<T1>(L, 1));
    push(L, retValue);
    return 1;
}

// example use
template<typename R, typename T1>
void push(R (*func)(T1))
{
    lua_pushlightuserdata(L, func);
    lua_pushcclosure(L, &arg1wrapper<R, T1>, 1);
}

( luaToC模板函数对于库打算支持的每个C和C++类型都是专门化的。类似地,push函数将被重载。)

您会注意到,上面这对函数只适用于一种特定类型的C函数,即具有非空返回值和单个参数的函数。可以通过将返回值操作分解成第三个专门用于void的模板来处理Void返回,但是要支持其他数量的参数,您需要一堆重载。luabind是这样做的:它对它所支持的每数量的参数都有一个重载,包括一个对于0的参数(最大值是他们选择的一些任意数字)。

(请注意,在C++0x中,可以使用可变模板来支持具有相同模板的任意数量的参数)

票数 3
EN

Stack Overflow用户

发布于 2011-05-25 00:39:04

我对luabind并不熟悉,但是“包装器”的全部思想是,它构建在一些较低级别的抽象之上,封装它。luabind几乎肯定在内部使用lua_State

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6114765

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档