无法映射到向量 <std::string>

Trouble mapping to vector<std::string>

我正在尝试为第三方库扩展 python 包装器。我是 swig 的新手,对 C++ 还很生疏,所以非常感谢您的帮助。

swig接口文件代码如下:

%include "std_list.i"
%include "std_map.i"
%include "std_vector.i"
%include "std_string.i"
%include "std_pair.i"
%include "std_shared_ptr.i"

%shared_ptr(std::vector<std::string>)

%define VECTORTEMPLATE_WRAP(vectorname, T)
%feature("ignore") vector<T>::append;
// a bunch more %feature("ignore")
%template(vector ## vectorname) vector<T>;
%enddef

VECTORTEMPLATE_WRAP(String, std::string)

我认为最后一部分只是更笼统的说法

%template(vectorString) vector<std::string>

然后在头文件中声明这个函数:

class OBCONV OBConversion
{
int FullConvert(std::vector<std::string>& FileList, std::string&
                OutputFileName, std::vector<std::string>& OutputFileList);
}

然而,当我构建整个项目并在 python 中调用此函数时:

conv = ob.OBConversion()
conv.FullConvert([],'',[])

我收到以下错误:

TypeError: in method 'OBConversion_FullConvert', argument 2 of type 'std::vector< std::string,std::allocator< std::string > > &'

在我看来,这似乎完全跳过了 %template 指令,可能是由于类型参数中的 "allocator"。

事实上,如果我查看这个函数的 swig 生成的 c++ 代码,我有

SWIGINTERN PyObject *_wrap_OBConversion_FullConvert(PyObject
     *SWIGUNUSEDPARM(self), PyObject *args) { PyObject *resultobj = 0;
OpenBabel::OBConversion *arg1 = (OpenBabel::OBConversion *) 0 ;
std::vector< std::string,std::allocator< std::string > > *arg2 = 0 ;
std::string *arg3 = 0 ;
std::vector< std::string,std::allocator< std::string > > *arg4 = 0 ;
// ...
}

我正在使用 c++11 进行构建,我不认为该项目最初是为此开发的,所以这可能与它有关。

什么是分配器以及如何让 swig 将向量映射到 python 列表?

What is the allocator...

std::string实际上是std::basic_string<char>,定义如下,默认实现为TraitsAllocator。 SWIG 只是显示这些默认值。

template< 
    class CharT, 
    class Traits = std::char_traits<CharT>, 
    class Allocator = std::allocator<CharT>
> class basic_string;

...how do I get swig to map the vector to a python list

SWIG 不会自动知道如何将 Python 列表转换为 stringVector。您可以获得一些免费功能(如下),或者您必须编写额外的类型映射来告诉 SWIG 如何将 Python 列表转换为向量。

这是一个使用字符串向量的工作 Windows 示例。请注意,正确使用 const 有助于 SWIG 了解使用输入类型映射与输出类型映射,我的示例具有输入向量和字符串以及输出向量:

test.h

#include <vector>
#include <string>

#ifdef API_EXPORTS
#   define API __declspec(dllexport)
#else
#   define API __declspec(dllimport)
#endif

API int FullConvert(const std::vector<std::string>& FileList, const std::string& OutputFileName, std::vector<std::string>& OutputFileList);

test.cpp

#include <iostream>
#include <vector>
#include <string>
#define API_EXPORTS
#include "test.h"

// Example to copy vin to vout
API int FullConvert(const std::vector<std::string>& FileList, const std::string& OutputFileName, std::vector<std::string>& OutputFileList)
{
    for(auto& file: FileList)
    {
        std::cout << file << std::endl;
        OutputFileList.push_back(file);
    }
    std::cout << OutputFileName << std::endl;
    return 1;
}

test.i

%module test

%{
#include "test.h"
%}

%include <windows.i>
%include <std_vector.i>
%include <std_string.i>

%template(stringVector) std::vector<std::string>;
%include "test.h"

输出

>>> import test
>>> vin = test.stringVector()
>>> vout = test.stringVector()
>>> vin.push_back('abc')
>>> vin.push_back('def')
>>> test.FullConvert(vin,'test',vout)
abc
def
test
1
>>> vout[0]
'abc'
>>> vout[1]
'def'