2010-09-10 3 views
0

J'écris un programme en python qui devrait pouvoir passer des "callables" qui sont enregistrés dans une classe C++. Jusqu'à présent, j'ai écrit le code suivant:Enregistrement d'appelables python dans les classes C++

C++:

class MyClass 
{ 
... 
public: 
    register_callback(boost::function<void (int)> fun); 
}; 

API Python/C:

class_<MyClass, boost::shared_ptr<MyClass>, boost::noncopyable>("MyClass", no_init) 
    .def("register_callback", &MyClass::register_callback); 

Le code compile, mais quand je l'appelle la méthode de python, le passage d'un appelable (dans mon cas, une autre méthode d'instance) je reçois l'erreur d'exécution suivante:

Boost.Python.ArgumentError: Python argument types in 
    MyClass.register_callback(MyClass, instancemethod) 
did not match C++ signature: 
    register_callback(MyClass {lvalue}, boost::function<void()(int)>) 

Je pense que j'ai besoin d'un moyen de dire boost, il peut passer un callable chaque fois qu'un boost :: fonction est nécessaire. Tout fonctionne si j'utilise une solution faite à la main:

void my_caller(MyClass* obj, object callable) 
{ 
    obj->register_callback(callable); // Works! 
} 

class_<MyClass, boost::shared_ptr<MyClass>, boost::noncopyable>("MyClass", no_init) 
    .def("register_callback", &my_caller); 

Comme je n'ai quelques fonctions de registre comme cela, je pouvais coller avec la solution à la main (avec des macros pour aider), mais je me demande comment peut Je dis à boost :: python de faire la conversion automatiquement. En regardant la documentation que j'ai trouvé la directive to_python_converter qui, ironiquement, fait exactement le contraire de ce que je dois ...

Répondre

1

Comme vous l'avez déduit, MyClass est passé en tant boost::python::object alors que register_callback veut un boost::function. Heureusement, la solution est assez simple - je pense. Votre code ressemblerait quelque chose comme celui-ci (non testé ) (adapté de http://mail.python.org/pipermail/cplusplus-sig/2010-February/015199.html):

... 
struct callable_wrapper_t 
{ 
    callable_wrapper_t(boost::python::object callable) : _callable(callable) {} 

    void operator()() 
    { 
     // These GIL calls make it thread safe, may or may not be needed depending on your use case 
     PyGILState_STATE gstate = PyGILState_Ensure(); 
     _callable(); 
     PyGILState_Release(gstate); 
    } 

    boost::python::object _callable; 
}; 
... 
class MyClass 
{ 
... 
public: 
    register_callback(boost::function<void (int)>(callback_wrapper_t(fun))); 
}; 
... 
class_<MyClass, boost::shared_ptr<MyClass>, boost::noncopyable>("MyClass", no_init) 
    .def("register_callback", &my_caller); 
... 

, vous pouvez également jeter un oeil à py_boost_function.hpp