gpt4 book ai didi

c++ - 如何使用 SWIG 从 lua 中的 C++ 类继承

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:45:26 29 4
gpt4 key购买 nike

比如有一个用C++写的类:

//Say.h
#pragma once

#include <iostream>

class Say
{
public:
Say() {}
virtual ~Say() {}
virtual void SaySomething() { std::cout << "It should not be show..\n"; };
};

inline void CallCppFun(Say& intf) {
intf.SaySomething();
}

然后我写了 Say.i:

//Say.i
%module Test

%{
#include "Say.h"
%}

%include "Say.h"

%inline %{
inline void CallCppFun(Say& intf);
%}

和 main.cpp:

//main.cpp
#include <iostream>

extern "C"
{
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
}

/* the SWIG wrappered library */
extern "C" int luaopen_Test(lua_State*L);

using namespace std;

int main()
{
lua_State *L;
L = luaL_newstate();
luaL_openlibs(L);
printf("[C] now loading the SWIG wrapped library\n");
luaopen_Test(L);
if (luaL_loadfile(L, "Test.lua") || lua_pcall(L, 0, 0, 0)) {
printf("[C] ERROR: cannot run lua file: %s", lua_tostring(L, -1));
exit(3);
}

return 0;
}

然后运行命令:

swig -c++ -lua say.i

我编译自动生成的文件 example_wrap.cxx 和其他 cpp 文件并成功链接。

我想在Test.lua中做的是在lua中继承C++的Say类:

-- Test.lua
Test.Say.SaySomething = function(self)
print("Inherit from C++ in Lua")
end

my = Test.Say()

my:SaySomething() -- doesn't appear to inherit successfully in lua call

Test.CallCppFun(my) -- doesn't appear to inherit successfully in c++ call

打印的结果在lua调用和c++调用中都没有出现继承成功:

[C] now loading the SWIG wrapped library
It should not be show..
It should not be show..

我知道在 Java 中支持从 C++ 继承:generating-java-interface-with-swig

我知道这里有一个类似的问题,但没有给出我面临的具体问题的答案:implementing-and-inheriting-from-c-classes-in-lua-using-swig

Lua 是否支持使用 SWIG 从 lua 中的 C++ 类继承,或者甚至只使用纯 lua?请显示一些代码示例。如果 SWIG 无法完成这项工作,它是否有一些第三方库支持可以轻松完成?

最佳答案

似乎 SWIG with Lua doesn't actually support directors 是跨语言多态性工作所必需的。但这还不是世界末日,看起来您的 SaySomething 方法是 Say 类中唯一的虚拟方法,因此您可以替换为单个回调函数。 (如果是我,我会在 C++ 接口(interface)设计中使用 std::function,这会稍微简化这项工作的其余部分)。

为了展示它是如何工作的(并在此过程中向我学习一些 Lua!)我整理了一个演示,它对问题中的测试用例进行了稍微简化。

本质上,我最终做的是修改 Callback 类的“in”类型映射,以使用 luaL_ref 保留对匿名函数的“引用”,当且仅当输入是given 不是回调类型。因此,我的类型映射检查它被赋予的类型,并构造一个临时的本地类型的实例,该实例继承自 Callback 类型,持有并使用对某些 Lua 定义代码的引用,直到我们用 lua_pcall 调用它.由于我们只在调用期间保留该实例,因此我们稍后会在 argfree 类型映射中清理它。 (我从 a Lua mailing list post 得到这个想法)

所以我的界面在一个地方演示了这一切,如下所示:

%module test

%{
#include <iostream>
%}

%typemap(in) const Callback& (Callback *tmp=NULL) %{
if(lua_isuserdata(L,$argnum)) {
if (!SWIG_IsOK(SWIG_ConvertPtr(L,$input,(void**)&$1,$descriptor,$disown))){
SWIG_fail_ptr("$symname",$argnum,$descriptor);
}
}
else if (lua_isfunction(L,$argnum)) {
struct Lua$basetype : $basetype {
Lua$basetype(lua_State* L, int idx) : L(L) {
lua_pushvalue(L, idx); // This gets popped by luaL_ref
// retain our argument
ref = luaL_ref(L, LUA_REGISTRYINDEX);
}
virtual ~Lua$basetype() {
// release our reference
luaL_unref(L, LUA_REGISTRYINDEX, ref);
}
virtual void run(const std::string& str) const {
// push our 'reference' onto the stack
lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
// manually prepare the function arguments
lua_pushstring(L, str.c_str());
// make the actual calll
lua_pcall(L, 1, 0, 0);
// TODO: catch error and throw as C++ exception?
}
private:
lua_State* L; // Uh, is keeping this around bad?
int ref;
};
tmp = new Lua$basetype(L,$input);
$1 = tmp;
}
else {
SWIG_fail_arg("$symname",$argnum,"$1_type");
}
%}

%typemap(freearg) const Callback& %{
delete tmp$argnum; // Fine, even if NULL remember
%}

%inline %{
struct Callback {
virtual ~Callback() {}
virtual void run(const std::string& str) const { std::cout << "Got string: " << str << "\n"; }
};

void call_me(const Callback& cb) {
std::cout << "Hello World:\n";
cb.run("DO IT NOW");
}
%}

这就足够了,我可以将它与以下 Lua 代码一起使用:

require("test")
cb=test.Callback()
test.call_me(cb)
cb=function(s) print("Lua got string: "..s) end
test.call_me(cb)

我可以编译和运行的:

swig3.0 -lua -c++ test.i
g++ -Wall -Wextra test_wrap.cxx -shared -o test.so -I /usr/include/lua5.1/
lua run.lua
Hello World:
Got string: DO IT NOW
Hello World:
Lua got string: DO IT NOW

请注意,这个示例几乎使我编写的 Lua 总量翻了一番,因此在用于生产之前,您真的应该检查我所做的是否合理。如果您更熟悉 Lua,可能可以使用类似这样的方法向 SWIG 添加适当的导向器支持,或者更好地模拟它(即,一种类型中有多个虚函数)。

关于c++ - 如何使用 SWIG 从 lua 中的 C++ 类继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39721608/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com