【发布时间】:2021-05-19 15:28:52
【问题描述】:
我正在尝试手动将指针向量从 C++ 绑定到 Lua。
我仅限于支持部分 C++11 的编译器,因此无法使用现有绑定库之一,因为它们现在似乎都在使用 C++17。
例如,我有一个包含指向子类的指针列表的类。从 Lua 的角度来看,children 的向量是只读的 - 我不需要添加、删除等。只需阅读。
class Child
{
public:
std::string name;
};
class Parent
{
public:
std::vector <Child *>children;
};
...
Parent parent;
Child * m = new Child;
m->name = "Mary";
parent.children.push_back(m);
Child * b = new Child;
b->name = "Bob";
parent.children.push_back(b);
...
子绑定。
static int Child_name(lua_State * lua) {
// this should get a point to a Child object and return the name
lua_pushstring(lua, "child name");
return 1;
}
static const struct luaL_Reg Child_FunctionList[] = {
{ "name", Child_name },
{ NULL, NULL }
};
static int Child_tostring(lua_State * lua) {
lua_pushstring(lua, "Child");
return 1;
}
static const struct luaL_Reg Child_MetaList[] = {
{ "__tostring", Child_tostring },
{ NULL, NULL }
};
void Child_Register(lua_State * lua)
{
luaL_newlib(lua, Child_FunctionList);
if(luaL_newmetatable(lua, "ChildMetaTable"))
luaL_setfuncs(lua, Child_MetaList, 0);
lua_setmetatable(lua, -2);
lua_pop(lua, 1);
}
父绑定。
static int Parent_count(lua_State * lua) {
// used by both the Parent function and metatable __len
lua_pushinteger(lua, parent.children.size());
return 1;
}
static int Parent_children(lua_State * lua)
{
// stack -1=number(1)
int idx = lua_tonumber(lua, -1);
Child ** c = static_cast<Child **>(lua_newuserdata(lua, sizeof(Parent *)));
*c = parent.children[idx];
luaL_getmetatable(lua, "ChildMetaTable"); // [-0, +1, m]
lua_setmetatable(lua, -2);
// return new userdata - does not work
return 1;
}
static const struct luaL_Reg Parent_FunctionList[] = {
{ "count", Parent_count },
{ "children", Parent_children },
{ NULL, NULL }
};
static int Parent_tostring(lua_State * lua) {
lua_pushstring(lua, "Parent");
return 1;
}
static int Parent_index(lua_State * lua) {
// stack -1=number(1) -2=table
int idx = lua_tonumber(lua, -1);
Child * c = parent.children[idx];
// what to return here?
return 0;
}
static const struct luaL_Reg Parent_MetaList[] = {
{ "__tostring", Parent_tostring },
{ "__len", Parent_count },
{ "__index", Parent_index },
{ NULL, NULL }
};
void Parent_Register(lua_State * lua) {
luaL_newlib(lua, Parent_FunctionList);
if(luaL_newmetatable(lua, "ParentMetaTable"))
luaL_setfuncs(lua, Parent_MetaList, 0);
lua_setmetatable(lua, -2);
lua_setglobal(lua, "Parent");
}
Parent 绑定会生成一个全局表,这是有意的。测试父表:
>print(Parent)
Parent
>print(#Parent)
2
>print(Parent.count())
2
但是尝试访问孩子也不起作用
>c = Parent[1]
>print(c)
Child
>print(type(c))
userdata
>print(c.name())
[string "main"]:8: attempt to index a ChildMetaTable value (global 'c')
我在Parent_index 中迷路了,我需要一个指向 C 父对象而不是 Lua 表的指针。我了解该方法是使用 userdata 或 lightuserdata 但看不到如何将类绑定到 Lua 以执行此操作。 Child 绑定也是如此,这会导致 ChildMetatable 但没有 Lua 表。
编辑:我在 Parent 下添加了一个子函数,但仍然无法正常工作。还将lua_setmetatable 的一些索引从堆栈底部更改为堆栈顶部(负数)
Edit2:这是因为我试图让 Parent:children 既作为表又作为用户数据。所以我可以返回带有 C 对象指针的 userdata 以及带有 __index 的 ChildMetaTable 以确定如何处理子方法。
【问题讨论】:
-
您应该在
Parent_count中使用lua_pushinteger而不是lua_pushnumber,因为将浮点数作为计数很奇怪。 -
您可能不想在
Parent_index中使用lua_pushlightuserdata,因为轻量级用户数据没有元表。您需要使用lua_newuserdatauv创建完整元数据。 -
谢谢。我已更改为
lua_pushinteger并更改了lua_setmetatable以使用堆栈顶部的索引。我试过创建用户数据,然后设置到Parent_children中的元表,但还没有。