对象与静态成员的lua/C++绑定
lua/C++ binding of objects with static members
我对如何将C++类转换为Lua类非常感兴趣。我发现了一个很好的助手类-LunaWrapper(此处描述)
但在Lua中,类本身唯一持久存在的东西(这里不讨论结果对象!)似乎只有构造函数。也就是说,我不能调用任何静态函数(如果有的话)。(例如,让我们在LunaWrapper页面上描述的示例中添加一个函数:
)
static bool Foo::bar(const char* text)
{
printf("in barn");
}
例如,我想在Lua做什么:
local foo = Foo()
foo:foo()
Foo.bar() -- this should output "in bar", but this wont work! And this is what I want.
foo.bar() -- this should also output "in bar", but this is probably going to work.
我该怎么做?
玩了一番之后,我想到了以下内容:
首先,向Luna添加另一个结构,并在类中的另一个表中定义静态函数(为了匹配LunaWrapper代码的风格,您可以使用任何您喜欢的方式来获取信息:
struct StaticRegType {
const char *name;
int(*mfunc)(lua_State*); // pointers to static members are C-style func pointers
// and are incompatible with int(T::*mfunc)() ones
};
...
static const Luna<Foo>::StaticRegType StaticRegister[];
...
const Luna<Foo>::StaticRegType Foo::StaticRegister[] = {
{ "bar", &Foo::bar },
{ 0 }
};
现在来看有趣的部分。不幸的是,事实证明,你必须对LunaWrapper进行大量更改,才能让它做你想做的事。我们将制作一个名为Foo的函数来调用构造函数,而不是制作一个名称为Foo,并用__call方法附加一个元表,这样我们就可以维护Foo()构造函数语法(这在Luna::Register中):
lua_newtable(L);
... // here we'll insert our manipulations of the table
lua_setglobal(L, T::className); // setglobal will pop the table off the stack
// so we'll do whatever we want to it and then give it
// a name to save ourselves the extra lookup
创建元表并添加构造函数和垃圾收集函数:
luaL_newmetatable(L, T::className);
lua_pushstring(L, "__gc");
lua_pushcfunction(L, &Luna<T>::gc_obj);
lua_settable(L, -3);
lua_pushstring(L, "__call");
lua_pushcfunction(L, &Luna<T>::constructor);
lua_settable(L, -3);
现在我们需要添加所有的方法。我们将使用__index元方法——两个选项:1。将__index设置为一个cfunction,该函数采用我们试图从lua调用的名称并运行该函数,或者2。将__index设置为一个包含我们所有函数的表(有关这两个选项的更多信息,请参阅本文)。我更喜欢后者,因为它可以避免我们循环使用所有函数,进行令人讨厌的字符串比较,并且我们可以进行一些复制和重用Luna的闭包。然而,它确实需要我们制作一个新的staticThunk
函数来处理我们的新方法:
static int staticThunk(lua_State *L) {
int i = (int)lua_tonumber(L, lua_upvalueindex(1));
return (*(T::StaticRegister[i].mfunc))(L);
}
注意,它要简单得多,因为我们不需要获取调用函数的对象(我也很喜欢模板抽象,让编译器处理触发对象的正确函数的细节,但这对Luna作者来说是一个很好的决定;)。
现在我们需要为__index制作一个表,并向其中添加方法。
lua_pushstring(L,"__index"));
lua_newtable(L);
// adding the normal methods is the same as in Luna (the for-loop over T::Register)
// add the static methods by going over our new StaticRegister array (remember to use
// staticThunk for them and thunk for the members
lua_settable(L, -3); // push the __index table to the metatable
快到了。。。以下是元表的技巧-我们已经构建了Foo表(即使它还没有真正命名为Foo),现在我们要将我们为对象构建的元表设置为它也是元表。通过这种方式,我们可以同时执行Foo.bar()
和local foo = Foo(); foo.bar()
:
lua_setmetatable(L, -2); // at this point the stack contains our metatable right under
// our table
lua_setglobal(L, T::className); // name the darn thing
你需要做的最后一件事是去掉Luna::constructor中与实际构建对象无关的任何东西(额外的好处-Register实际上注册了对象类型,而constructor实际上只是分配它,如果你问我的话,它应该是这样的)。我们将原来在这里的循环移到了Register函数中。我们完了!
注意:这个解决方案的一个缺点是,虽然为了方便起见,它允许您同时调用Foo.bar()
和foo.bar()
,但它也允许您调用Foo.foo()
,这没有意义,并且在编译等效的C/C++程序时会被视为非法尝试调用成员函数,但会因Lua中的运行时错误而失败。如果你想摆脱这种行为,你必须为Foo表创建一个不包括成员函数的元表,为你创建的包含成员函数的对象创建另一个元表。
- 我想将一个对T类型的非常量左值引用绑定到一个T类型的临时值
- 在基于范围的for循环中使用结构化绑定声明
- 使用 LuaBridge 将 LuaJIT 绑定到C++会导致"PANIC: unprotected error"
- 尝试通过OCI例程从Oracle获取blob数据,但出现错误:ORA-01008:并非所有变量都绑定
- 在使用GPU支持编译Tensorflow时,会遇到CUDA_TOOLKIT_PATH未绑定变量
- 视觉studo 2019中的漫画和静态/动态绑定
- 将自由函数绑定为类成员函数
- 将常量指针引用绑定到非常量指针
- 在派生类中绑定非静态模板化成员函数
- 绑定派生类方法C++从实例范围之外的分隔 std::function 变量调用
- 在 openGL 中多次绑定缓冲区
- 定义有趣的宏和正则表达式在Z3 C++绑定
- 使用结构化绑定'Reflection'
- 为什么 std::绑定错误参数可以成功?
- 如何绑定 C++ gRPC 客户端的网络接口
- 在 openmp 中,omp_get_thread_num是否绑定到物理线程?
- C++绑定(已弃用)
- 运行时错误:引用绑定到类型为"int"的空指针
- 有没有办法将重载的类函数绑定到函数对象?
- 替换 C++17 中移除的绑定 1st