2009-10-16 5 views
2

Je suis en train d'ajouter un rappel python à une bibliothèque C++ comme illustré:rappel Python avec SWIG enveloppé le type

template<typename T> void doCallback(shared_ptr<T> data) { 
    PyObject* pyfunc; //I have this already 
    PyObject* args = Py_BuildValue("(O)", data); 
    PyEval_CallObject(pyfunc,args); 
} 

Cela échoue parce que les données n'a pas connu rasade, et n'est pas un PyObject.

J'ai essayé d'utiliser:

swigData = SWIG_NewPointerObj((void*)data, NULL, 0); 

Mais parce que son modèle, je ne sais pas vraiment ce qu'il faut utiliser pour le second paramètre. Même si je code dur le SWIGTYPE 'correct', il se sépare généralement sur PyEval_CallObject.

Mes questions sont les suivantes:

  1. Quelle est la meilleure façon d'invoquer l'emballage de type rasade ? Je vais même dans la bonne direction ici? Les administrateurs ont l'air promettant d'implémenter un rappel , mais je n'ai pas pu trouver un exemple de de directeurs avec python.

Mise à jour: L'emballage approprié est généré obtenir. J'ai d'autres fonctions qui retournent shared_ptrs et peuvent les appeler correctement.

+0

Merci pour votre mise à jour, mais je suppose que je suis confus. Pourquoi ne pas simplement passer vos données shared_ptr à votre fonction Python? Pourquoi avoir un doCallback() du tout? –

+0

Ma bibliothèque enveloppe une bibliothèque C++ existante. doCallback() est simplement un gestionnaire que la lib sous-jacente appelle de temps en temps. Pour être clair: je n'appelle jamais doCallback() de Python. – rogueg

+0

Ah, bien sûr! J'ai ajouté une nouvelle réponse qui pourrait mieux vous servir. –

Répondre

0

Ma première réponse mal compris la question complètement, donc nous allons essayer encore une fois.

Votre problème central est le paramètre de type libre T dans la définition de doCallback. Comme vous l'avez souligné dans votre question, il n'y a aucun moyen de faire un objet SWIG sur un shared_ptr<T> sans valeur concrète pour T: shared_ptr<T> n'est pas vraiment un type.

Ainsi, je pense que vous devez vous spécialiser: pour chaque instanciation concrète de doCallback que le système hôte utilise, fournissez une spécialisation de modèle pour le type cible. Avec cela fait, vous pouvez générer un enveloppement Python-friendly de data, et passez-le à votre fonction python. La technique la plus simple pour cela est probablement:

swigData = SWIG_NewPointerObj((void*)(data.get()), SWIGType_Whatever, 0); 

...Bien que cela ne fonctionne que si votre fonction Python n'enregistre pas son argument n'importe où, le shared_ptr lui-même n'est pas copié.

Si vous devez conserver une référence à data, vous devez utiliser le mécanisme généralement utilisé par SWIG pour renvoyer shared_ptr. S'il n'y a pas de magie cas spécial smart-pointeur en cours, il est probablement quelque chose comme:

pythonData = new shared_ptr<Whatever>(data); 
swigData = SWIG_NewPointerObj(pythonData, SWIGType_shared_ptr_to_Whatever, 1); 

Peu importe, vous vous avez un objet SWIG Python convivial qui est prête à Py_BuildValue().

Espérons que cela aide.

+0

Cela a du sens. J'espérais qu'il y avait un moyen magique d'insérer le SWIGType_really_long_name dans mon code, mais je suppose que non. – rogueg

0

shared_ptr<T> pour T inconnu n'est pas un type, donc SWIG ne peut pas espérer l'envelopper. Ce que vous devez faire est de fournir un emballage SWIG pour chaque instance de shared_ptr que vous avez l'intention d'utiliser. Donc, si par exemple vous voulez être en mesure de doCallback() à la fois shared_ptr<Foo> et shared_ptr<Bar>, vous aurez besoin:

  • Un emballage pour Foo
  • Un emballage pour Bar
  • wrappers pour shared_ptr<Foo> et shared_ptr<Bar>.

Vous faites ceux comme ceci:

namespace boost { 
    template<class T> class shared_ptr 
     { 
     public: 
      T * operator->() const; 
     }; 
    } 

%template(FooSharedPtr) boost::shared_ptr<Foo>; 
%template(BarSharedPtr) boost::shared_ptr<Bar>; 
+0

Merci pour la réponse David! Malheureusement, j'ai déjà le code que vous décrivez, donc un emballage est généré. – rogueg