Klassen in Swig

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
tc09
User
Beiträge: 10
Registriert: Montag 17. August 2009, 08:43

Hallo zusammen,
ich habe ein Problem mit Swig und hoffe dass mir dabei vielleicht jemand helfen kann. Ich benutze Swig, um einige Python-Extensions in C++ zu erstellen, die sowohl als Eingabe-Argument als auch als Ausgabe-Argument Vektoren enthalten. In Python verwende ich für diese Vektoren einfach Listen mit float-Werten und in C++ benutze ich den vector-typ aus der Standardbibliothek. Um die Dateikonvertierung zwischen C++ und Python durchzuführen benutze ich die folgenden Typemappings:

%typemap(in) std::vector<double> {
int i,len;
len = PySequence_Length($input);
std::vector<double> VecIn(len);
for (i = 0; i < len; i++) {
PyObject *o = PySequence_GetItem($input,i);
VecIn=PyFloat_AsDouble(o);
}
$1=VecIn;
}

%typemap(out) std::vector<double> {
std::vector<double> Out;
int i,len;
Out=$1;
len = Out.size();
$result = PyList_New(len);
for (i = 0; i < len; i++) {
PyObject *o = PyFloat_FromDouble((double) Out);
PyList_SetItem($result,i,o);
}
}

Für Funktionen funktioniert dieses Typemapping auch sehr gut. Wenn ich allerdings in einer C++Klasse eine Methode habe, die einen Vektor zurückgibt, dann klappt das mit dem Typemapping nicht mehr.
Muss man für Klassen das Typemapping irgendwie anders definieren?? Komischerweise funktioniert es nämlich, wenn man einen solchen Pythonvector an eine C++Klasse als Eingabeargument übergibt, bloß die Ausgabe macht Probleme.
Ich bin für jeden Tipp dankbar.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Hallo und willkommen im Forum,

reichen nicht einfach:

Code: Alles auswählen

%include stl.i
/* instantiate the required template specializations */
namespace std {
    %template(IntVector)    vector<int>;
    %template(DoubleVector) vector<double>;
    %template(vvDouble)     vector<vector<double> >; 
}
und ähnliche Definitionen?

Gruß,
Christian
tc09
User
Beiträge: 10
Registriert: Montag 17. August 2009, 08:43

Ich muss meine Frage nochmal ein klein wenig korrigieren: Also die Eingabe und die Ausgabe funktioniert mit diesem Typemapping auch für Klassen, aber wenn ich versuche von Python auf ein Attribut (vom Typ Vector) der C++ Klasse zuzugreifen, funktioniert das Typemapping nicht, anscheinend wird es für nicht auf diese Attribute sondern nur auf die Eingabe und die Ausgabeargumente angewendet. Ist es irgendwie möglich ein Typemapping zu definieren, das auch auf diese Attribute angewendet wird???
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Code: Alles auswählen

%module mymodule
%{
#include "MyClass.h"
%}

template<class T1>
struct wrap {
   typedef T1 first_type;
   T1 first_name;
   wrap();
   wrap(const T1&);
  ~wrap();
};

%template(wrapvf) wrap<std::vector<double >>;
In Python

Code: Alles auswählen

import mymodule
x = mymodule.wrapvf([1.0, 2.0])
print x.first_name
Ungetestet - müsste funktionieren.

Gruß,
Christian
tc09
User
Beiträge: 10
Registriert: Montag 17. August 2009, 08:43

Hallo CM,
das hab ich noch nie ausprobiert, sieht aber schön einfach aus :-)
Muss man das einfach statt den Typemappings ins Interface-File schreiben?? Oder muss man dann auch noch etwas an den Funktions-Definitionen oder im Interface-File ändern??
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

tc09 hat geschrieben:Muss man das einfach statt den Typemappings ins Interface-File schreiben?? Oder muss man dann auch noch etwas an den Funktions-Definitionen oder im Interface-File ändern??
Das kommt drauf an. Wenn Du sie für die Memberfunktionen brauchst, solltest Du die Maps wohl drin lassen.

Im Übrigen gibt es eine gute Mailingliste. Da kannst Du Dein .i-File auch herzeigen. Meinereiner jedenfalls kommt ohne allzuviel Code und Rumprobieren ins Schwimmen ;-).

Gruß,
Christian
tc09
User
Beiträge: 10
Registriert: Montag 17. August 2009, 08:43

Vielen Dank schonmal für die schnellen Antworten.
Leider bekomme ich deinen Lösungsvorschlag nicht zum Laufen, was wahrscheinlich auch an meinen mangelnden C++ Kenntnissen liegt. Am praktischsten wäre auch eine Lösung, die nicht für alle Attribute extra definiert werden muss, sondern auf alle Attribute aller Klassen angewendet werden kann, so wie bei dem normalen Typemapping.
Gibt es vielleicht irgendwo Beispieldateien in denen solch ein Typemapping für Klassen benutzt wird?? Und wo findet man diese Mailingliste??
Gruß,
Tim
tc09
User
Beiträge: 10
Registriert: Montag 17. August 2009, 08:43

Oder irgendein Tutorial in dem das Typemapping für Klassen behandelt wird, würde mir auch schon weiterhelfen.
tc09
User
Beiträge: 10
Registriert: Montag 17. August 2009, 08:43

So,
falls es noch jemanden interessiert, ich habs inzwischen zum Laufen bekommen indem ich im Interface-File die gewünschten Klassenparameter aufgelistet habe und zusätzlich folgendes Typemapping ergänzt habe:

%typemap(varout) std::vector<double> {
std::vector<double> Out;
int i,len;
Out=$1;
len = Out.size();
$result = PyList_New(len);
for (i = 0; i < len; i++) {
PyObject *o = PyFloat_FromDouble((double) Out);
PyList_SetItem($result,i,o);
}
}

Man muss also nur darauf achten, dass die Typemappings nicht nur für (in) und (out) sondern auch für (varin) und (varout) vorhanden sind.
[/quote]
Benutzeravatar
mkesper
User
Beiträge: 919
Registriert: Montag 20. November 2006, 15:48
Wohnort: formerly known as mkallas
Kontaktdaten:

Benutze doch bitte

Code: Alles auswählen

Code-Tags!
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Hoi,

die Mailinglisten findest Du hier: http://www.swig.org/mail.html
Und wie gesagt, diese Typemaps scheinen mir etwas umständlich. Und auch schwer zu pflegen.

Gruß,
Christian
tc09
User
Beiträge: 10
Registriert: Montag 17. August 2009, 08:43

Diese template-Lösung die du zuerst für das Typemapping vorgeschlagen hast, würde ich auch viel lieber verwenden. Ich glaube das ist das gleiche, wie in den Swig-examples unter std_vector. Das Problem ist, dass ich auch bei dem Swig-Beispiel direkt über 40 Fehler bekomme. Hier mal der erste Fehler als Beispiel:
error C2989: 'noconst_traits<Type>' : template class has already been defined as a non-template class
Ich kann mit dem Fehler ehrlich gesagt nichts anfangen. Kann es sein dass das Swig-Beispiel nicht Microsoft Visual C++ geeignet ist?? Oder muss für diese templates noch irgendwas dazuinstalliert werden??
Gruß
Tim
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Bzgl. Compiler: Keine Ahnung. Ist Dein Code irgendwo gehostet?
tc09
User
Beiträge: 10
Registriert: Montag 17. August 2009, 08:43

Das Beispiel von dem ich gesprochen hab liegt unter Swig\Examples\python\std_vector müsste glaub ich bei jeder Swig-Insatallation gleich sein.
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Oh, interessant. Aber was ich meine ist: Wo liegt DEIN Code? Ohne den können wir lange raten woran es liegen könnte ... Zur Not geht sicher auch ein Pastbin. (Und geht vielleicht ein Minimalbeispiel?)
tc09
User
Beiträge: 10
Registriert: Montag 17. August 2009, 08:43

Ok, also hier ein etwas minimiertes Beispiel das zwar funktioniert, aber noch nicht ganz meinen Vorstellungen entspricht:

HeaderDatei:

Code: Alles auswählen

#include <vector>
using namespace std;

class MeineKlasse
{
public:
	static std::vector<double> parameter;	
	MeineKlasse(std::vector<double> init_param)
	{
		parameter = init_param;
	}
};
InterfaceFile:

Code: Alles auswählen

%module ExtensionModule


%include "std_vector.i"

%{
#include "HeaderDatei.h"
std::vector<double> MeineKlasse::parameter;
%}

%typemap(in) std::vector<double> {
  int i,len;
  len = PySequence_Length($input);
  std::vector<double> VecIn(len);
  for (i = 0; i < len; i++) {
	PyObject *o = PySequence_GetItem($input,i);
	VecIn[i]=PyFloat_AsDouble(o);
  }
  $1=VecIn;
}

%typemap(varout) std::vector<double> {
  std::vector<double> Out;
  int i,len;
  Out=$1;
  len = Out.size();
  $result = PyList_New(len);
  for (i = 0; i < len; i++) {
	PyObject *o = PyFloat_FromDouble((double) Out[i]);
	PyList_SetItem($result,i,o);
	}
}

%include "HeaderDatei.h"
std::vector<double> MeineKlasse::parameter;
In Python kann das Ganze dann wie folgt aufgerufen werden:

Code: Alles auswählen

import  ExtensionModule
MK = ExtensionModule.MeineKlasse([1.,2.,3.])
print 'Attribut=',MK.parameter

>>> 
Attribut= [1.0, 2.0, 3.0]
>>> 
Das funktioniert soweit auch ganz gut, allerdings möchte ich eigentlich nicht, dass das Attribut "parameter" static ist
Das habe ich aber bisher nicht hinbekommen. Eigentlich hätte ich gedacht dass man dann im Interface-File statt "std::vector<double> MeineKlasse::parameter;" das hier "std::vector<double> MeineKlasse.parameter;" verwendet, das liefert aber immer SyntaxError.
Mit dieser Template-Geschichte könnte man das wahrscheinlich schöner lösen, nach langer Internet-Recherche und Ausprobieren glaube ich allerdings dass VC++ 6 ein Problem mit templates hat. Außerdem wüsste ich auch gerne wie das mit meinem etwas umständlicherem Typemapping funktioniert.
Wäre super, wenn mir da jemand weiterhelfen kann.
Schöne Grüße
Tim
tc09
User
Beiträge: 10
Registriert: Montag 17. August 2009, 08:43

So, inzwischen hab ich selbst rausgefunden wie es funktioniert.
Am Ende des Interface-Files muss man die folgenden zwei Zeilen anhängen:

Code: Alles auswählen

%typemap(in) std::vector<double> * "/* my in typemap */"
%typemap(out) std::vector<double> * "/* my out typemap */"
Dann wird das Typemapping auch für Klassen-Attribute durchgeführt. Ich weiß zwar nicht wieso, aber es funktioniert.
Antworten