2010-09-10 4 views
0

Я пишу программу на python, которая должна иметь возможность передавать «callables», которые зарегистрированы в классе C++. До сих пор я написал следующий код:Регистрация вызовов python в классах C++

C++:

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

Python/C API:

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

Код компилируется, но когда я вызываю метод из питона, пропусканием (в моем случае, другой метод экземпляра) Я получаю следующую ошибку времени выполнения:

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)>) 

Я думаю, мне нужен способ сказать, что он может безопасно проходить вызов каждый раз, когда требуется функция boost ::. Все работает, если я использую ручное решение:

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); 

Поскольку у меня есть только несколько функций регистра, как это я мог бы придерживаться с ручным решением (с помощью макросов, чтобы помочь), , но мне интересно, как можно Я говорю boost :: python, чтобы сделать преобразование автоматически. Глядя на документации, которую я нашел директиву to_python_converter, которая, вполне иронично, делает именно то, наоборот, что мне нужно ...

ответ

1

Как вы сделать вывод, MyClass в настоящее время передается в качестве boost::python::object в то время как register_callback хочет boost::function. К счастью, решение достаточно простое, я думаю. Ваш код будет выглядеть что-то вроде этого (непроверенных) (адаптировано из 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); 
... 

Кроме того, вы можете захотеть взглянуть на py_boost_function.hpp

Смежные вопросы