I'm trying to wrap some C++ functions into a Python wrapper. For this, it seems SWIG is a nice and easy way.
Wrapping works, but I get a problem when passing integers by reference or by pointer. Since Python cannot work with references, SWIG internally converts these to pointers.
Some simple example code:
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"
Than convert the code into a Python wrapper:
#!/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
This all works fine. Now, I start Python and do:
from Blaat import *
a = Blaat()
b = int(1)
a.setA(b) <-- fine, calls setA() function fine
a.getA(b) <-- does not work
At the "getA()" call, the following error occurs:
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 &'
Note that I get this problem both when passing the argument by reference and by pointer. Looking at the generated "Blaat_wrap.cxx" file, it stops at the actual type conversion:
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 &""'");
}
This means that the function SWIG_ConvertPtr() fails, which is strange because it seems that the type it checks for is SWIGTYPE_p_int. From the "setA()" function, we see that the type conversion works (if passing by value).
The SWIG documentation tells me):
C++ references are supported, but SWIG transforms them back into pointers. For example, a declaration like this :
class Foo { public: double bar(double &a); }
has a low-level accessor
double Foo_bar(Foo *obj, double *a) { obj->bar(*a); }
Can someone throw in the thing I'm missing? I'm quite stuck at this point... Found this post, but this did not help either
I don't think python has the concept of return by reference, but here is my solution:
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()
Running:
python b.py
[Blaat::setA] fA = 1
[Blaat::getA] fA = 63
Thanks Chris, this works! After a bit of more digging, it seems that the SWIG documentation is not complete.
SWIG type conversion using the typemaps.i library is described here. What I get from the example is that you HAVE to manually specify that you want an argument to be used as output (which means that the SWIG documentation on 'pointers and references' only holds for INPUT arguments only!).
For the simple example above, it is sufficient to just including the .hpp file and let SWIG handle everything automatically.
Blaat.i:
%module Blaat
%include typemaps.i
%apply int &OUTPUT { int & fA };
%{
#include "Blaat.hpp"
%}
%include "Blaat.i"
PS: The Blaat.cpp file couts the wrong value, it should of course cout mA instead of fA since fA is set after the cout...
精彩评论