SWIG C ++ Python: упаковка int по ссылке или по указателю - PullRequest
9 голосов
/ 15 июля 2011

Я пытаюсь обернуть некоторые функции 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 голосов
/ 15 июля 2011

Я не думаю, что в 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
2 голосов
/ 21 июля 2011

Спасибо, Крис, это работает!После нескольких копаний кажется, что документация SWIG не завершена.

Преобразование типов SWIG с использованием библиотеки typemaps.i описано здесь .Из этого примера видно, что вы ДОЛЖНЫ указать вручную, что вы хотите, чтобы аргумент использовался в качестве выходных данных (это означает, что документация SWIG о «указателях и ссылках» сохраняется только для аргументов INPUT!).* Для простого примера, приведенного выше, достаточно просто включить файл .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 ...

...