Boost.Python中函数作为参数传递的调用失败问题求解
解决Boost.Python传递可调用对象到std::function参数的问题
问题根源
Boost.Python默认没有提供std::function<int(int)>与Python可调用对象(包括暴露的C++函数、函数对象实例、Python自定义函数)之间的类型转换逻辑,导致调用ExecuteFunction时出现参数类型不匹配错误。
方案一:注册std::function类型转换器
通过自定义Boost.Python类型转换器,让框架能够识别并转换Python侧的可调用对象为std::function<int(int)>类型。修改后的完整代码如下:
#include <boost/python.hpp> #include <boost/python/to_python_converter.hpp> #include <functional> typedef std::function<int(int)> Function; // 实现Python可调用对象到std::function的转换器 struct Function_from_python { Function_from_python() { boost::python::converter::registry::push_back( &convertible, &construct, boost::python::type_id<Function>() ); } // 检查对象是否可调用 static void* convertible(PyObject* obj_ptr) { return PyCallable_Check(obj_ptr) ? obj_ptr : nullptr; } // 构造std::function包装器 static void construct( PyObject* obj_ptr, boost::python::converter::rvalue_from_python_stage1_data* data) { using namespace boost::python; object callable(handle<>(borrowed(obj_ptr))); // 分配内存并构造std::function void* storage = ((converter::rvalue_from_python_storage<Function>*)data)->storage.bytes; new (storage) Function( [callable](int x) { return extract<int>(callable(x)); } ); data->convertible = storage; } }; int ExecuteFunction(int x, Function f) { return f(x); }; int Half(int x) { return x / 2; }; struct Square { int operator()(int x) const { return x * x; }; }; BOOST_PYTHON_MODULE(Test) { // 注册转换器 Function_from_python(); boost::python::def("ExecuteFunction", ExecuteFunction); boost::python::def("Half", Half); boost::python::class_<Square>("Square") .def("__call__", &Square::operator()); };
代码说明
Function_from_python结构体实现了Boost.Python的转换接口:convertible函数通过PyCallable_Check判断Python对象是否可调用(覆盖所有实现__call__的对象);construct函数创建std::function实例,内部捕获Python可调用对象,调用时自动完成参数和返回值的类型转换。
- 在模块初始化时注册转换器,让Boost.Python识别该转换规则。
方案二:直接使用boost::python::object作为参数
如果不需要在C++代码中使用std::function的其他特性,可以简化实现,直接用boost::python::object接收可调用对象:
#include <boost/python.hpp> int ExecuteFunction(int x, boost::python::object f) { return boost::python::extract<int>(f(x)); }; int Half(int x) { return x / 2; }; struct Square { int operator()(int x) const { return x * x; }; }; BOOST_PYTHON_MODULE(Test) { boost::python::def("ExecuteFunction", ExecuteFunction); boost::python::def("Half", Half); boost::python::class_<Square>("Square") .def("__call__", &Square::operator()); };
代码说明
- 直接用
boost::python::object接收所有Python可调用对象; - 通过
f(x)调用对象,并用extract<int>提取返回值,自动完成类型转换。
验证效果
修改后,Python侧的以下调用均可正常执行:
import Test def Double(x): return x * 2 a = Test.ExecuteFunction(2, Test.Half) # 返回1 b = Test.ExecuteFunction(2, Test.Square()) # 返回4 c = Test.ExecuteFunction(2, Double) # 返回4
内容的提问来源于stack exchange,提问作者akerstjens
相关产品推荐
相关产品推荐

