如何使用SWIG为C ++ std :: vector生成Lua迭代器?

在 SWIG 2.0.8 的 lua/std_vector.i 文件中有这样一段注释:

但不支持迭代器和插入/删除操作。

但也许有人知道如何做到?

例如,可以通过定义 __len 添加 # 长度运算符(可能是偶然的,我是通过试错找到的):

%include "std_vector.i"
%extend std::vector { int __len(void*) { return self->size(); } }
namespace std {
    %template(PointVector) vector<fityk::Point>;
}

我尝试使用类似的技巧来定义 __call,但我卡住了。SWIG 封装成了障碍。我尝试使用 %native,但我无法让它与 %extend 一起工作。

点赞
用户104453
用户104453

我不知道如何在 SWIG 模板中完成此操作,但我成功地从 C++ 向 SWIG 生成的元表中插入了 __call,在调用 luaopen_module 后:

    SWIG_Lua_get_class_metatable(L_, PointVector);
    SWIG_Lua_add_function(L_, "__call", lua_vector_iterator);

因此,该向量可以用作迭代器。有点笨拙,但可以工作:

> = points
<PointVector userdata: 190FBE8>
> for n, p in points do print(n, p) end
0       (24.0154; 284; 16.8523)
1       (24.0541; 343; 18.5203)

该迭代器返回索引和值,类似于 Python 中的 enumerate(),Lua 将索引再次传回迭代器(栈上的第三个参数)。我没有看到此行为的文档,因此可能依赖于实现细节。

以下是用作 __call() 的函数:

// SWIG-wrapped vector is indexed from 0. Return (n, vec[n]) starting from n=0.
static int lua_vector_iterator(lua_State* L)
{
    assert(lua_isuserdata(L,1)); // in SWIG everything is wrapped as userdata
    int idx = lua_isnil(L, -1) ? 0 : lua_tonumber(L, -1) + 1;

    // no lua_len() in 5.1, let's call size() directly
    lua_getfield(L, 1, "size");
    lua_pushvalue(L, 1); // arg: vector as userdata
    lua_call(L, 1, 1);   // call vector<>::size(this)
    int size = lua_tonumber(L, -1);

    if (idx >= size) {
        lua_settop(L, 0);
        return 0;
    }

    lua_settop(L, 1);
    lua_pushnumber(L, idx); // index, to be returned
    lua_pushvalue(L, -1);   // the same index, to access value
    lua_gettable(L, 1);     // value, to be returned
    lua_remove(L, 1);
    return 2;
}
2012-10-26 22:35:25