【问题标题】:Lua callback from C++来自 C++ 的 Lua 回调
【发布时间】:2013-12-04 18:30:23
【问题描述】:

我有一个 c++ 主机,我在其中使用 tolua++ 向 Lua 公开一些类。其中一个类有一个函数,应该从 lua 注册回调。所以当 C++ 代码需要调用一个 Lua 注册的函数时它可以。然而,该函数是一个表/类函数。我以前用字符串函数名(不是lua“类”的一部分)成功地做到了这一点,但我很好奇我是否能够以某种方式存储Lua函数而不是函数名。

我将我的 lua 类定义为:

MyClass = {}

function MyClass:Create()
    local obj = {}

    -- copy all functions from MyClass table to this local obj and return it
    local k,v
    for k,v in pairs(obj) do
        obj[k] = v
    end

    return obj
end

function MyClass:Enter()
    self.CPlusClass = CPlusClass:Create()   -- this is the C++ class creation, I defined a static function Create()
    self.CPlusClass:RegisterCallback(15, self.Callback) -- this is where I want to pass this instances function to be called back from the C++ class
end

function MyClass:Callback(reader)
    -- I want to be able to use self here as well so it needs to be the same instance
end

在 MyClass:Enter() 内部是我想注册 lua“类”函数 MyClass::Callback 以便能够从 C++ 对象调用的地方。我如何将它传递给 C++ 函数?什么样的类型才能从 C++ 调用 MyClass:Callback() 并传入“self”,这样它就是类的同一个“实例”?

所以我知道'self'指的是我创建的一个实际变量,我假设它将按变量名在全局表中,但是当你在 lua“类”中时,我怎么知道变量名'self '也是指?如果我能得到它,我可以将它传递给我的 C++ 函数并将其存储为字符串,以便我可以在其上调用 getglobal 以获取该特定表,然后我还可以将表函数名称作为字符串传递,并且在 C++ 中我可以也得到它,然后调用它。但问题是,如何将“self”转换为它所指向的实际变量名,以便我可以在 C++ 中调用 getglobal 来获取该表?

【问题讨论】:

  • self 不是全局变量,self 是由 table:function 语法糖定义的自动变量。 function table:class(args...) ... endfunction table.class(self, args...) ... end 相同。同样,对tab:class(args...) 的调用与tab.class(tab, args...) 相同(尽管选项卡只评估一次)。
  • 我明白这一点。然而,self 指的是我在 lua 程序中某处创建的表。我怎么知道 self 指的是什么变量名?
  • 您不能将函数与其表“对象”取消关联,并让它稍后再次在该表“对象”上工作。你需要创建一个闭包作为你的回调函数来做你想做的事情。
  • self 是变量名。它是函数的第一个参数。它是调用函数的表。
  • 但 self 指的是我在 lua 程序某处创建的表,不是吗?该表变量名必须在全局表中不是吗?

标签: c++ lua


【解决方案1】:

您将 CPlusClass“类”从 C++ 导出到 Lua:当然,这个 C++ 类有一个 RegisterCallback,它接受一个指向函数的指针或一个 YourCallbackClass 实例,该实例使用虚方法分派到正确的对象。然后您只需将 YourCallbackClass 导出到 Lua:在幕后,Lua 版本将创建一个实例并将其提供给您的 C++ RegisterCallback。 例如:

class CPlusClass {
public: 
    RegisterCallback(int val, CPlusCallback* cb) { ... store cb for later... }
};

class SomeObj; // type of Objects that you want to call back into

class CPlusCallback {
public:
    typedef void (SomeObj::*Method)();
    CPlusCallback(SomeObj* obj, Method method) { callee=obj; method=method; }
    call() { callee->*Method(); }
private:
    SomeObj* callee; 
    Method method;
};

您的 CPlusCallback 可能有所不同,这只是一个示例。例如,如果您只想要函数而不是方法,那么您不需要存储被调用者。如果两者都需要,那么 CPlusCallback 必须是基类,并且 call() 是虚拟的,派生类实现适当的细节。适应你的情况。

然后将CPlusCallback和SomeObj导出到Lua,就可以在Lua中做:

somObj = SomeObj:Create()

function MyClass:Enter()
    -- creates Lua instance of CPlusClass, with a user data for the C++
    -- counterpart as member
    self.CPlusClass = CPlusClass:Create()  
    self.CPlusCallback = CPlusCallback:Create(someObj, someObj.method)
    self.CPlusClass:RegisterCallback(15, self.CPlusCallback)
end

上面假设 someObj.method 是您从 C++ 类 SomeObj 导出的方法,具有正确的签名 void (SomeObj::*Method)()。

【讨论】:

  • 感谢您提供替代方法。目前我得到了发送self的方法,然后是lua类的字符串方法名称并从C++中调用它。与您在这里所做的非常相似。我很关心它是如何完成的,但我想通了。
【解决方案2】:

如果您想保留RegisterCallback 签名和操作(而不是增强它以以某种方式理解对象方法回调),那么您需要创建一个闭包并将其作为回调传递。像这样的:

function create_closure(obj, fun)
    return function(...)
        return obj[fun](...)
    end
end

function MyClass:Enter()
    self.CPlusClass = CPlusClass:Create()   -- this is the C++ class creation, I defined a static function Create()
    self.CPlusClass:RegisterCallback(15, create_closure(self, "Callback"))
end

【讨论】:

  • 我的 RegisterCallback() 的第二个参数实际上是一个字符串。我最初的希望是能够获取 self 所指的变量名并将其连接为“obj:Callback”,然后在 C++ 函数中将其分解。如果我使用这种方法,第二个参数需要是什么?
  • RegisterCallback 需要一个字符串?它假设命名了一个可以稍后查找的全局函数?
  • 这是一个字符串,因为我的想法是能够查找具有该函数的表名,这意味着它假设它是全局的。我是唯一一个处理这个的人,所以我控制它。但是更改参数并不是什么大不了的事,但我只需要知道闭包返回什么以及我的 C++ 函数期望什么类型。此外,我的 C++ 程序会将 lightuserobject 的 1 个参数传递给闭包。我假设 ... 自动处理所有参数?
  • 闭包不会为此返回任何东西。闭包 create_closure 的返回,闭包只是一个函数。您不能直接在 C++ 中存储 lua 函数(除非您的绑定为您处理必要的工作)。您存储的是对已知表中函数的引用,然后在需要时再次查找。有关此想法的 lua api 示例,请参见 lua 手册中的 luaL_ref。是的,... 是 lua 可变参数。
  • 所以重点是能够从 C++ 调用 lua 函数,所以我必须在 C++ 中存储一些东西才能在某个时候从 C++ 调用它。在过去没有类的情况下,我会传入一个 lua 函数的字符串名称,这样我就可以得到它并从 C++ 中调用它。现在这是一个“类”函数,我仍然需要存储一些东西以便以后能够从 C++ 调用它。由于它是匿名的,它没有名字,但我假设它在某个地方的全局表中(只是没有名字?)。 lua 在幕后是否给了它一些我可以在 C++ 中查找来调用它的价值?
猜你喜欢
  • 2013-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-13
  • 2013-08-19
  • 2014-08-06
相关资源
最近更新 更多