包装的 C++ 函数的输入字符串不会更改 SWIG

Input sting for wrapped C++ function doesn't changing SWIG

我为 C++ 库制作 Python 包装器。

mylib.i:

%module mylib
%include <std_string.i>

%{
    #include "mylib.h"

%}
%apply const std::string & {std::string &};
%apply std::string & {std::string &};

int getResult(const std::string& path, std::string& result);

mylib.h:

#pragma once

#include <string>

myEnum {foo=0, bar};
myEnum getResult(const std::string& path, std::string& result);

使用以下命令生成 _mylib.so 后:

g++ -fPIC -Wall -Wextra -shared mylib_wrap.cxx -o _mylib.so -L. -lmylib -I/usr/include/python2.7/ -lpython2.7

接下来我做:

LD_LIBRARY_PATH=. python Python 2.7.2 (default, Dec  6 2016, 10:43:39) 
[GCC 4.8.4] on linux4
Type "help", "copyright", "credits" or "license" for more information.
>>> import _mylib
>>> result= ""
>>> x = _mylib.getResult("somePath",result)

执行我的功能后,x return 方法的正确响应。我的函数也有控制台输出。但结果字符串没有改变。 如果我用 "some text" 初始化结果字符串,然后再次调用我的函数,print result return "some text"。我做错了什么?

无论 SWIG 在这种情况下做了多少诡计,它都无法回避 python 字符串不可变的事实 - 一旦设置,就无法更改它们。

SWIG 生成的代码大致如下所示:

std::string *arg1 = make a new std::string from path;
std::string *arg2 = make a new std::string from result;
result = (int)getResult((std::string const &)*arg1,*arg2);
resultobj = SWIG_From_int(static_cast< int >(result));
if (SWIG_IsNewObj(res1)) delete arg1;
if (SWIG_IsNewObj(res2)) delete arg2;

请注意,它会根据传入的字符串创建一个新字符串,然后在最后对它们进行核对 - 毕竟,字符串是不可变的。

一个懒惰的解决方案就是 returning json 字符串,例如接口:

std::string getResult(std::string &path)

会有想要的效果。

现在,如果您想要一个特殊的 return 值,它就是对象以及其中包含的所有内容。

让这个在您的界面中工作的最简单方法是使用 %inline 创建一个重载 return 结果:

%module mylib
%include <std_string.i>

%{
    #include "mylib.h"
%}

%inline %{
    int getResult(const std::string& path) {
        std::string temp;
        const int ret = getResult(path, temp);
        if (ret != good) abort(); // TODO exceptions
        return temp;
    }
%}

您甚至不需要向 SWIG 展示 getResult 的真实版本。

还有其他选项(例如,使用 numinputs=0 的输入类型映射和 argout 类型映射来修改 return 值),但它们更复杂,而且通常更难移植到其他语言。