绑定C++;指向Lua的向量 我试图手动将C++中的指针向量绑定到Lua。

绑定C++;指向Lua的向量 我试图手动将C++中的指针向量绑定到Lua。,c++,lua,C++,Lua,我仅限于一个部分支持C++11的编译器,因此无法使用现有的绑定库,因为它们现在似乎都使用C++17 例如,我有一个类,其中包含指向子类的指针列表。从Lua的角度来看,子向量是只读的-我不需要添加、删除等。只需阅读即可 class Child { public: std::string name; }; class Parent { public: std::vector <Child *>children; }; ... Parent parent;

我仅限于一个部分支持C++11的编译器,因此无法使用现有的绑定库,因为它们现在似乎都使用C++17

例如,我有一个类,其中包含指向子类的指针列表。从Lua的角度来看,子向量是只读的-我不需要添加、删除等。只需阅读即可

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 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");
}
但是试图接近孩子们也不管用

>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\u index
中,在这里我需要一个指向C Parent对象的指针,而不是Lua表。我理解这个方法是使用userdata或lightuserdata,但不知道如何将类绑定到Lua来实现这一点。子绑定也是如此,它生成一个ChildMetatable,但没有Lua表

编辑:我在父项下添加了一个children函数,但仍然不起作用。还将
lua_setmetatable
的一些索引从堆栈底部更改为堆栈顶部(负数)


Edit2:这是因为我试图让Parent:children同时充当表和用户数据。因此,我可以使用C对象指针返回userdata,同时返回带有_索引的ChildMetaTable,以确定如何处理子方法。

我试图做的是同时拥有Lua表和userdata

首先,最好用表中为子对象创建新用户数据的函数替换父
\u index
方法

static int Parent_children(lua_State * lua)
{
    int idx = luaL_checkinteger(lua, -1);
    Parent * p = &parent;
    luaL_argcheck(lua, (idx >= 0) && (idx < (int)p->children.size()), 1, "index out of range");

    Child ** pc = static_cast<Child **>(lua_newuserdata(lua, sizeof(Child *)));
    *pc = parent.children[idx];
    luaL_getmetatable(lua, "ChildMetaTable"); // [-0, +1, m]
    lua_setmetatable(lua, -2);
    return 1;
}
static const struct luaL_Reg Parent_MetaList[] = {
    { "__tostring", Parent_tostring },
    { NULL, NULL }
};
子方法从userdata中获取一个C指针

static int Child_name(lua_State * lua)
{
    Child * c = *reinterpret_cast<Child **>(luaL_checkudata(lua, -1, "ChildMetaTable"));
    lua_pushstring(lua, c->name.c_str());
    return 1;
}
这可能不是最佳解决方案,但正朝着这个方向发展

编辑: 全局
父级
可以在展开的
luaL_newlib
宏中作为upvalue传递,而不是使用全局
父级

luaL_newlibtable(lua, Parent_FunctionList);
lua_pushlightuserdata(lua, parent);
luaL_setfuncs(lua, Parent_FunctionList, 1);
...

static int Parent_children(lua_State * lua) {
Parent * parent= (Parent *)(lua_topointer(lua, lua_upvalueindex(1)));
...

您应该在
Parent\u count
中使用
lua\u pushinteger
而不是
lua\u pushnumber
,因为使用浮点数作为计数是很奇怪的。您可能不想在
Parent\u index
中使用
lua\u pushlightuserdata
,因为轻用户数据没有元表。您需要使用
lua\u newuserdatauv
创建完整的元数据。谢谢。我已更改为
lua\u pushinteger
,还更改了
lua\u setmetatable
以使用堆栈顶部的索引。我尝试过创建userdata,然后在
Parent\u children
中设置元表,但仍然没有。
static int Child_index(lua_State * lua)
{
    const char * fn_name = luaL_checkstring(lua, -1);
    for(const luaL_Reg * fn = Child_FunctionList; fn->name != NULL; fn++)
    {
        if(strcmp(fn_name, fn->name) == 0)
        {
            lua_pushcfunction(lua, fn->func);
            return 1;
        }
    }
    return 0;
}
static const struct luaL_Reg Child_MetaList[] = {
    { "__tostring", Child_name },
    { "__index", Child_index },
    { NULL, NULL }
};
static int Child_name(lua_State * lua)
{
    Child * c = *reinterpret_cast<Child **>(luaL_checkudata(lua, -1, "ChildMetaTable"));
    lua_pushstring(lua, c->name.c_str());
    return 1;
}
void Child_Register(lua_State * lua)
{
    if(luaL_newmetatable(lua, "ChildMetaTable"))
        luaL_setfuncs(lua, Child_MetaList, 0);
    lua_pop(lua, 1);
}
luaL_newlibtable(lua, Parent_FunctionList);
lua_pushlightuserdata(lua, parent);
luaL_setfuncs(lua, Parent_FunctionList, 1);
...

static int Parent_children(lua_State * lua) {
Parent * parent= (Parent *)(lua_topointer(lua, lua_upvalueindex(1)));
...