为 returns 向量对的函数创建 SWIG 类型映射
Creating a SWIG typemap for function that returns vector of pairs
我正在尝试创建一个 getter 函数,该函数 return 是 Lua 中的对向量。
我在 C++ 中有以下矢量数据:
{{1, "a"}, {2, "b"}, {3, "c"}}
我想 return 这个向量作为 Lua 中的 table 所以它可以与 [=53= 中的 table t
相同]:
local t = {};
t[1].value = 1
t[1].name = "a"
t[2].value = 2
t[2].name = "b"
t[3].value = 3
t[3].name = "c"
这是我的代码:
"MyBindings.h
"
#include "main.h"
class MyClass
{
public:
MyClass()
:MyData({{1, "a"}, {2, "b"}, {3, "c"}}){}
void getMyData(std::vector<pair<float, std::string>> *datap)
{
*datap = MyData;
}
std::vector<pair<float, std::string>> MyData;
};
"MyBindings.i
"
%module my
%{
#include "MyBindings.h"
%}
%include <stl.i>
%include <typemaps.i>
%include <std_string.i>
%include <std_vector.i>
/* convert the output std::vector<pair<float, std::string>> to lua_Table */
%typemap(in, numinputs = 0) (std::vector<pair<float, std::string>> *datap)
(std::vector<pair<float, std::string>> *tdatap = nullptr)
%{
%}
%typemap(argout) (std::vector<pair<float, std::string>> *datap)
{
lua_newtable(L);
for (size_t i = 0; i < ->size(); ++i)
{
lua_newtable(L);
lua_pushinteger(L, static_cast<lua_Number>(->at(i).first));
lua_setfield(L, -2, "value");
lua_pushstring(L, ->at(i).second.c_str());
lua_setfield(L, -2, "name");
lua_rawseti(L, -2, i + 1);
}
SWIG_arg++;
}
%include "MyBindings.h"
"main.cpp
"
#include "main.h"
#include "lua.hpp"
extern "C"
{
int luaopen_my(lua_State *L);
}
int main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaopen_my(L);
lua_settop(L, 0);
luaL_dostring(L, "local c = my.MyClass()\n"
"local t = c:getMyData()\n"
"print('Value : ' .. t[2].value)\n"
"print('Name : ' .. t[2].name)\n");
lua_close(L);
}
我想要的结果:
Value : 2
Name : b
我得到的结果:
vector: Thread 1: EXC_BAD_ACCESS (code=1, address=0x10)
我应该如何更改我的代码以获得我想要的结果?
基本上解决方案是不使用输出参数 (argout
)。这实际上是对 C++ 编程的一般建议。在 C 时代,输出参数是必需的,因为您无法通过值从函数中轻松 return 数组。
经过一些重构后,我得到以下结果:
MyBindings.h
#include <string>
#include <utility>
#include <vector>
class MyClass {
std::vector<std::pair<float, std::string>> m_data;
public:
MyClass() : m_data({{1, "a"}, {2, "b"}, {3, "c"}}) {}
std::vector<std::pair<float, std::string>> data() { return m_data; }
};
MyBindings.i
%module my
%{
#include "MyBindings.h"
%}
%typemap(out) std::vector<std::pair<float, std::string>>
{
lua_newtable(L);
for (size_t i = 0; i < .size(); ++i)
{
lua_newtable(L);
lua_pushinteger(L, static_cast<lua_Number>(.at(i).first));
lua_setfield(L, -2, "value");
lua_pushstring(L, .at(i).second.c_str());
lua_setfield(L, -2, "name");
lua_rawseti(L, -2, i + 1);
}
SWIG_arg++;
}
%include "MyBindings.h"
main.cpp
#include "lua.hpp"
extern "C"
{
int luaopen_my(lua_State *L);
}
int main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaopen_my(L);
lua_settop(L, 0);
luaL_dostring(L, "local c = my.MyClass()\n"
"local t = c:data()\n"
"print('Value : ' .. t[2].value)\n"
"print('Name : ' .. t[2].name)\n");
lua_close(L);
}
调用示例:
$ swig -c++ -lua MyBindings.i
$ clang++ -Wall -Wextra -Wpedantic -std=c++11 -I/usr/include/lua5.3 MyBindings_wrap.cxx main.cpp -llua5.3
$ ./a.out
Value : 2
Name : b
我正在尝试创建一个 getter 函数,该函数 return 是 Lua 中的对向量。
我在 C++ 中有以下矢量数据:
{{1, "a"}, {2, "b"}, {3, "c"}}
我想 return 这个向量作为 Lua 中的 table 所以它可以与 [=53= 中的 table t
相同]:
local t = {};
t[1].value = 1
t[1].name = "a"
t[2].value = 2
t[2].name = "b"
t[3].value = 3
t[3].name = "c"
这是我的代码:
"MyBindings.h
"
#include "main.h"
class MyClass
{
public:
MyClass()
:MyData({{1, "a"}, {2, "b"}, {3, "c"}}){}
void getMyData(std::vector<pair<float, std::string>> *datap)
{
*datap = MyData;
}
std::vector<pair<float, std::string>> MyData;
};
"MyBindings.i
"
%module my
%{
#include "MyBindings.h"
%}
%include <stl.i>
%include <typemaps.i>
%include <std_string.i>
%include <std_vector.i>
/* convert the output std::vector<pair<float, std::string>> to lua_Table */
%typemap(in, numinputs = 0) (std::vector<pair<float, std::string>> *datap)
(std::vector<pair<float, std::string>> *tdatap = nullptr)
%{
%}
%typemap(argout) (std::vector<pair<float, std::string>> *datap)
{
lua_newtable(L);
for (size_t i = 0; i < ->size(); ++i)
{
lua_newtable(L);
lua_pushinteger(L, static_cast<lua_Number>(->at(i).first));
lua_setfield(L, -2, "value");
lua_pushstring(L, ->at(i).second.c_str());
lua_setfield(L, -2, "name");
lua_rawseti(L, -2, i + 1);
}
SWIG_arg++;
}
%include "MyBindings.h"
"main.cpp
"
#include "main.h"
#include "lua.hpp"
extern "C"
{
int luaopen_my(lua_State *L);
}
int main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaopen_my(L);
lua_settop(L, 0);
luaL_dostring(L, "local c = my.MyClass()\n"
"local t = c:getMyData()\n"
"print('Value : ' .. t[2].value)\n"
"print('Name : ' .. t[2].name)\n");
lua_close(L);
}
我想要的结果:
Value : 2
Name : b
我得到的结果:
vector: Thread 1: EXC_BAD_ACCESS (code=1, address=0x10)
我应该如何更改我的代码以获得我想要的结果?
基本上解决方案是不使用输出参数 (argout
)。这实际上是对 C++ 编程的一般建议。在 C 时代,输出参数是必需的,因为您无法通过值从函数中轻松 return 数组。
经过一些重构后,我得到以下结果:
MyBindings.h
#include <string>
#include <utility>
#include <vector>
class MyClass {
std::vector<std::pair<float, std::string>> m_data;
public:
MyClass() : m_data({{1, "a"}, {2, "b"}, {3, "c"}}) {}
std::vector<std::pair<float, std::string>> data() { return m_data; }
};
MyBindings.i
%module my
%{
#include "MyBindings.h"
%}
%typemap(out) std::vector<std::pair<float, std::string>>
{
lua_newtable(L);
for (size_t i = 0; i < .size(); ++i)
{
lua_newtable(L);
lua_pushinteger(L, static_cast<lua_Number>(.at(i).first));
lua_setfield(L, -2, "value");
lua_pushstring(L, .at(i).second.c_str());
lua_setfield(L, -2, "name");
lua_rawseti(L, -2, i + 1);
}
SWIG_arg++;
}
%include "MyBindings.h"
main.cpp
#include "lua.hpp"
extern "C"
{
int luaopen_my(lua_State *L);
}
int main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
luaopen_my(L);
lua_settop(L, 0);
luaL_dostring(L, "local c = my.MyClass()\n"
"local t = c:data()\n"
"print('Value : ' .. t[2].value)\n"
"print('Name : ' .. t[2].name)\n");
lua_close(L);
}
调用示例:
$ swig -c++ -lua MyBindings.i
$ clang++ -Wall -Wextra -Wpedantic -std=c++11 -I/usr/include/lua5.3 MyBindings_wrap.cxx main.cpp -llua5.3
$ ./a.out
Value : 2
Name : b