Expose C++ member function that has std::function as argument with boost::python

不羁的心 提交于 2019-12-11 13:37:51

问题


I have a class that contains an attribute which is a std::function. I set the value of this attribute using a member function, so the class looks like this:

class ClassName
{    
public:
    void SetCallbackFunction(std::function<void (int i)> callbackFun) {
        m_callbackFunction = callbackFun;
    }

protected:
    std::function<void (int i)> m_callbackFunction;
};

I need to expose this class to Python and, of course, I need to expose the SetCallbackFunction function. How can I do this with boost::python?


回答1:


As Python objects are both Callable and CopyConstructible, the simplest approach is to expose an auxiliary function as SetCallbackFunction that accepts a boost::python::object, then delegates to the actual SetCallbackFunction function:

void ClassName_SetCallbackFunction_aux(ClassName& self, boost::python::object object)
{
  self.SetCallbackFunction(object);
}

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<ClassName>("ClassName", python::init<>())
    .def("set_callback", &ClassName_SetCallbackFunction_aux)
    // ...
    ;
}

When ClassName::SetCallbackFunction is directly exposed to Python and invoked, Boost.Python will search its registry at runtime to locate a from-Python converter for std::function<void (int)>. As this conversion has not been explicitly registered, Boost.Python will fail to dispatch the function call. The auxiliary function avoids this runtime conversion check and constructs a std::function<void (int)> object from a boost::python::object, as the boost::python::object is both Callable and CopyConstructible.


Here is an example demonstrating using an auxiliary function to assign Python objects as callbacks:

#include <functional> // std::function
#include <boost/python.hpp>

// Legacy API.
class spam
{
public:
  void SetCallbackFunction(std::function<void (int)> callback)
  {
    callback_ = callback;
  }

  void perform(int x)
  {
    callback_(x);
  }

private:
  std::function<void (int)> callback_;
};

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  // Expose spam.
  python::class_<spam>("Spam", python::init<>())
    // Use an auxiliary function to set Python callbacks.
    .def("set_callback", +[](spam& self, boost::python::object object) {
      self.SetCallbackFunction(object);
    })
    .def("perform", &spam::perform)
    ;
}

Interactive usage:

>>> import example
>>> called = False
>>> def perform_x(x):
...     assert(42 == x)
...     global called
...     called = True
... 
>>> spam = example.Spam()
>>> spam.set_callback(perform_x)
>>> assert(not called)
>>> spam.perform(42)
>>> assert(called) # Verify callback was invoked
>>> spam.set_callback(lambda: None)
>>> try:
...     spam.perform(42)
...     assert(False) # Verify callback fails (the lambda accepts no args)
... except TypeError:
...     pass
... 


来源:https://stackoverflow.com/questions/33875004/expose-c-member-function-that-has-stdfunction-as-argument-with-boostpython

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!