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]