python - 使用 boost::python 公开具有 std::function 作为参数的 C++ 成员函数

标签 python c++ c++11 boost boost-python

我有一个包含一个属性的类,它是一个 std::function。我使用成员函数设置此属性的值,因此该类如下所示:

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

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

我需要向 Python 公开此类,当然,我需要公开 SetCallbackFunction 函数。 我如何使用 boost::python 做到这一点?

最佳答案

由于 Python 对象都是 Callable 和 CopyConstructible,最简单的方法是公开一个辅助函数为 SetCallbackFunction接受 boost::python::object , 然后委托(delegate)给实际的 SetCallbackFunction功能:

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)
    // ...
    ;
}

ClassName::SetCallbackFunction直接暴露给 Python 并被调用,Boost.Python 将在运行时搜索其注册表以找到 std::function<void (int)> 的来自 Python 的转换器.由于此转换尚未显式注册,因此 Boost.Python 将无法分派(dispatch)函数调用。辅助函数避免了这种运行时转换检查并构造了一个 std::function<void (int)>。来自 boost::python::object 的对象, 作为 boost::python::object是 Callable 和 CopyConstructible。


这是一个例子 demonstrating使用辅助函数将 Python 对象分配为回调:

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

交互使用:

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

关于python - 使用 boost::python 公开具有 std::function 作为参数的 C++ 成员函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33875004/

相关文章:

python - 如何使用flask-cache和memcached?

python - 给定一个 8 位字节,以该字节的二进制表示形式生成 "ones"的序列和计数(使用最小化查找表)

c++ - 无法使用来自不同目录中不同源文件的 Makefile 进行编译

c++ - std::vector<int> 到 std::vector<enum>

c++ - 在C++中与libmongoclient链接时出错

c++ - std::scoped_allocator_adaptor 和一个使用 std::allocator_arg_t 构造函数的类

python 非阻塞 non-messing-my-tty 按键检测

python - MySQL 提交触发器完成

c++ - 如何构建 Qt Quick 2d 渲染器?

c++ - build2: 编译器不支持模块