You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 18:06:40