SWIG 未正确处理枚举向量
vector of enum not correctly handled by SWIG
亲爱的,
我使用 SWIG 生成到 C++ API 的 Python 绑定(并且效果很好!)但是我很难包装一个以枚举向量作为参数的函数。我已经构建了一个最小示例来简化调试,我将其作为此问题的附件。在我看来,该示例应该有效,至少它适用于整数参数的向量。
需求非常简单:我们有一个具有以下签名的 C++ 方法:
void Run(const std::vector<double> & in, std::vector<int> & out, std::vector<testing::Status> & status)
其中 testing::Status
是一个枚举
我们希望获得一个 Python 方法,例如:
out, status = Run(in)
使用附带的例子,swig可执行文件没有报错,Python运行方法可以运行,但是不能使用输出值状态,一个出现错误:
status: (<Swig Object of type 'testing::Status *' at 0x7fa441156450>, <Swig Object of type 'testing::Status *' at 0x7fa441156660>) swig/python detected a memory leak of type 'testing::Status *', no destructor found. swig/python detected a memory leak of type 'testing::Status *', no destructor found.
以下是可用于重现错误的不同文件:
mylib.h,要包装在 Python
中的 C++
#include <vector>
namespace testing
{
typedef enum
{
Ok = 0,
Error = 1,
} Status;
class Algo
{
public:
void Run(const std::vector<double> & in, std::vector<int> & out, std::vector<testing::Status> & status)
{
status.resize(in.size());
out.resize(in.size());
for (int i=0; i<in.size(); ++i) {
out[i] = i;
status[i] = Status::Ok;
}
}
};
}
mymodule.i,SWIG接口文件
%module mymodule
%{
#include "mylib.h"
%}
%include "std_vector.i"
%include "typemaps.i"
%define STD_TEMPLATE(TYPE...)
%template() TYPE;
%apply TYPE& OUTPUT {TYPE&}
%typemap(argout) const TYPE& {
// do nothing for const references
}
%typemap(out) (TYPE&) = (const TYPE&);
%enddef
STD_TEMPLATE (std::vector <int>);
STD_TEMPLATE (std::vector <double>);
STD_TEMPLATE (std::vector < testing::Status >);
%include "mylib.h"
build.sh,用于编译二进制文件的构建命令行
${swig_install}/bin/swig \
-I. \
-I${swig_install}/share/swig/${swig_version}/python \
-I${swig_install}/share/swig/${swig_version} \
-c++ -python \
-outdir . \
-o "mymodule.cxx" \
"mymodule.i"
g++ -L${python_install}/lib -lpython3 \
-I${python_install}/include/python \
-I. \
-std=c++11 -shared -fPIC \
mymodule.cxx -o _mymodule.so
run.py,Python中引发错误的例子
import mymodule as mm
algo = mm.Algo()
out, status = algo.Run([1.1, 2.2])
print("out:", out)
print("status:", status)
SWIG 不知道如何处理枚举输出向量。一种方法是自己处理类型图:
mylib.i
%module mylib
%{
#include "mylib.h"
%}
%include "std_vector.i"
%include "typemaps.i"
%define STD_TEMPLATE(TYPE...)
%template() TYPE;
%apply TYPE& OUTPUT {TYPE&}
%typemap(argout) const TYPE& {
// do nothing for const references
}
%typemap(out) (TYPE&) = (const TYPE&);
%enddef
STD_TEMPLATE (std::vector <int>);
STD_TEMPLATE (std::vector <double>);
// Don't require an input parameter in Python.
// Create a temporary vector to hold the output result.
%typemap(in,numinputs=0) std::vector<testing::Status>& (std::vector<testing::Status> tmp) %{
= &tmp;
%}
// Create a Python list object the same size as the vector
// and copy and convert the vector contents into it.
%typemap(argout) std::vector<testing::Status>& (PyObject* list) %{
list = PyList_New(->size());
for(int x = 0; x < ->size(); ++x)
PyList_SET_ITEM(list, x, PyLong_FromLong(->at(x)));
$result = SWIG_Python_AppendOutput($result, list);
%}
%include "mylib.h"
输出(与 mylib.h 和 run.py 相同):
out: (0, 1)
status: [0, 0]
亲爱的, 我使用 SWIG 生成到 C++ API 的 Python 绑定(并且效果很好!)但是我很难包装一个以枚举向量作为参数的函数。我已经构建了一个最小示例来简化调试,我将其作为此问题的附件。在我看来,该示例应该有效,至少它适用于整数参数的向量。
需求非常简单:我们有一个具有以下签名的 C++ 方法:
void Run(const std::vector<double> & in, std::vector<int> & out, std::vector<testing::Status> & status)
其中 testing::Status
是一个枚举
我们希望获得一个 Python 方法,例如:
out, status = Run(in)
使用附带的例子,swig可执行文件没有报错,Python运行方法可以运行,但是不能使用输出值状态,一个出现错误:
status: (<Swig Object of type 'testing::Status *' at 0x7fa441156450>, <Swig Object of type 'testing::Status *' at 0x7fa441156660>) swig/python detected a memory leak of type 'testing::Status *', no destructor found. swig/python detected a memory leak of type 'testing::Status *', no destructor found.
以下是可用于重现错误的不同文件:
mylib.h,要包装在 Python
中的 C++#include <vector>
namespace testing
{
typedef enum
{
Ok = 0,
Error = 1,
} Status;
class Algo
{
public:
void Run(const std::vector<double> & in, std::vector<int> & out, std::vector<testing::Status> & status)
{
status.resize(in.size());
out.resize(in.size());
for (int i=0; i<in.size(); ++i) {
out[i] = i;
status[i] = Status::Ok;
}
}
};
}
mymodule.i,SWIG接口文件
%module mymodule
%{
#include "mylib.h"
%}
%include "std_vector.i"
%include "typemaps.i"
%define STD_TEMPLATE(TYPE...)
%template() TYPE;
%apply TYPE& OUTPUT {TYPE&}
%typemap(argout) const TYPE& {
// do nothing for const references
}
%typemap(out) (TYPE&) = (const TYPE&);
%enddef
STD_TEMPLATE (std::vector <int>);
STD_TEMPLATE (std::vector <double>);
STD_TEMPLATE (std::vector < testing::Status >);
%include "mylib.h"
build.sh,用于编译二进制文件的构建命令行
${swig_install}/bin/swig \
-I. \
-I${swig_install}/share/swig/${swig_version}/python \
-I${swig_install}/share/swig/${swig_version} \
-c++ -python \
-outdir . \
-o "mymodule.cxx" \
"mymodule.i"
g++ -L${python_install}/lib -lpython3 \
-I${python_install}/include/python \
-I. \
-std=c++11 -shared -fPIC \
mymodule.cxx -o _mymodule.so
run.py,Python中引发错误的例子
import mymodule as mm
algo = mm.Algo()
out, status = algo.Run([1.1, 2.2])
print("out:", out)
print("status:", status)
SWIG 不知道如何处理枚举输出向量。一种方法是自己处理类型图:
mylib.i
%module mylib
%{
#include "mylib.h"
%}
%include "std_vector.i"
%include "typemaps.i"
%define STD_TEMPLATE(TYPE...)
%template() TYPE;
%apply TYPE& OUTPUT {TYPE&}
%typemap(argout) const TYPE& {
// do nothing for const references
}
%typemap(out) (TYPE&) = (const TYPE&);
%enddef
STD_TEMPLATE (std::vector <int>);
STD_TEMPLATE (std::vector <double>);
// Don't require an input parameter in Python.
// Create a temporary vector to hold the output result.
%typemap(in,numinputs=0) std::vector<testing::Status>& (std::vector<testing::Status> tmp) %{
= &tmp;
%}
// Create a Python list object the same size as the vector
// and copy and convert the vector contents into it.
%typemap(argout) std::vector<testing::Status>& (PyObject* list) %{
list = PyList_New(->size());
for(int x = 0; x < ->size(); ++x)
PyList_SET_ITEM(list, x, PyLong_FromLong(->at(x)));
$result = SWIG_Python_AppendOutput($result, list);
%}
%include "mylib.h"
输出(与 mylib.h 和 run.py 相同):
out: (0, 1)
status: [0, 0]