0

我正在用 python 编写一个程序,它应该能够传递在 C++ 类中注册的“callables”。到目前为止,我已经编写了以下代码:

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

代码可以编译,但是当我从 python 调用该方法时,传递一个可调用的(在我的情况下是另一个实例方法),我收到以下运行时错误:

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 他可以在每次需要 boost::function 时安全地传递一个可调用对象。如果我使用手工制作的解决方案,一切正常:

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 指令,具有讽刺意味的是,它与我需要的完全相反......

4

1 回答 1

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

于 2010-09-11T08:00:30.877 回答