SWIG C++ Python:通过引用或指针包装int

10
我想把一些C++函数封装成Python包装器。为此,SWIG似乎是一个不错且易于使用的方式。
封装工作正常,但在通过引用或指针传递整数时出现问题。由于Python无法处理引用,因此SWIG在内部将其转换为指针。
以下是一些简单的示例代码:
Blaat.hpp:
#ifndef __BLAAT_HPP__
#define __BLAAT_HPP
class Blaat
{
public:
 int mA;
 float mB;

public:
 Blaat() {}
 void getA(int & fA);
 void setA(const int fA);
 ~Blaat() {}
};

#endif // __BLAAT_HPP__

Blaat.cpp

#include "Blaat.hpp"
#include <iostream>

void Blaat::getA(int & fA) {
 std::cout << "[Blaat::getA] fA = " << fA << std::endl;
 fA = mA;
} 

void Blaat::setA(const int fA) {
 std::cout << "[Blaat::setA] fA = " << fA << std::endl;
 mA = fA;
}

Blaat.i:

%module Blaat
%{
/* Includes the header in the wrapper code */
#include "Blaat.hpp"
%}

/* Parse the header file to generate wrappers */
%include "Blaat.hpp"

然后将代码转换为Python包装器:

#!/bin/sh
swig -python -c++ -v $1.i 
gcc -c $1_wrap.cxx -fPIC -I/usr/include/python2.6
gcc -shared $1_wrap.o -o _$1<library_path> so -L. -l$1

这一切都很好运行。现在,我启动Python并执行:
from Blaat import *
a = Blaat()
b = int(1)
a.setA(b) <-- fine, calls setA() function fine
a.getA(b) <-- does not work

在调用"getA()"时,出现了以下错误:

Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "Blaat.py", line 86, in getA
   def getA(self, *args): return _Blaat.Blaat_getA(self, *args)
TypeError: in method 'Blaat_getA', argument 2 of type 'int &'

请注意,当我通过引用和指针传递参数时,都会遇到这个问题。 查看生成的“Blaat_wrap.cxx”文件,它停在实际类型转换处:
res2 = SWIG_ConvertPtr(obj1, &argp2, SWIGTYPE_p_int,  0 );
if (!SWIG_IsOK(res2)) {
 SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "Blaat_getA" "', argument " "2"" of type '" "int &""'"); 
}

这意味着函数 SWIG_ConvertPtr() 失败, 这很奇怪,因为它似乎检查的类型是 SWIGTYPE_p_int。 从 "setA()" 函数中,我们可以看到类型转换是有效的(如果通过值传递)。

SWIG 文档告诉我):

C++ 引用是支持的,但是 SWIG 将它们转换回指针。例如,像这样的声明 :

class Foo { public: double bar(double &a); }

有一个低级的访问器

double Foo_bar(Foo *obj, double *a) { obj->bar(*a); }

有人能帮我解决问题吗?我在这一点上非常困难... 找到了这篇帖子,但也没有帮助

2个回答

7
我认为Python没有返回引用的概念,但这里是我的解决方案:
Blaat.i:
%module Blaat
%include typemaps.i
%apply int &OUTPUT { int & fA };
%{
/* Includes the header in the wrapper code */
#include "Blaat.hpp"
%}

/* Parse the header file to generate wrappers */
class Blaat
{
public:
 Blaat();
 void getA(int & fA);
 void setA(const int fA);
 ~Blaat();
};

b.py:

from Blaat import *
a = Blaat()
b = int(1)
a.setA(b)
b = a.getA()

运行中:

python b.py
[Blaat::setA] fA = 1
[Blaat::getA] fA = 63

1
谢谢你的回答,Chris。确实,这是最简单的解决方案,只需通过值返回即可。但是,根据SWIG的文档,应该可以使用引用...所以,这就是我想要的! :) - RobW
1
在这里找到了一个类似的线程 - RobW

2

谢谢Chris,这个有效!

经过更深入的挖掘,似乎SWIG文档不完整。

在这里描述了使用typemaps.i库进行SWIG类型转换。从例子中得出的结论是,必须手动指定要将参数用作输出(这意味着关于“指针和引用”的SWIG文档仅适用于输入参数!)。

对于上面的简单示例,只需包括.hpp文件并让SWIG自动处理即可。

Blaat.i:

%module Blaat
%include typemaps.i
%apply int &OUTPUT { int & fA };
%{
#include "Blaat.hpp"
%}

%include "Blaat.i"

PS:Blaat.cpp文件输出了错误的值,当然应该输出mA而不是fA,因为fA是在cout之后设置的...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接