SWIG C++ Python: wrapping int by reference or pointer

RobW picture RobW · Jul 15, 2011 · Viewed 9.8k times · Source

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

Answer

Chris Card picture Chris Card · Jul 15, 2011

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