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

pybind11绑定带抽象类型引用参数的lambda函数时遇到非可复制类型错误

pybind11绑定带抽象类型引用参数的lambda函数时遇到非可复制类型错误

这个问题我之前也踩过坑,核心是pybind11默认的对象传递策略和抽象类的特性冲突了,咱们一步步捋清楚:

为什么会报“非可复制类型”错误?

当你在Python里调用evaluate时,C侧会创建一个内部的Foo实例,然后把它的引用IFoo&传给Python的回调函数。这时候pybind11需要把C的引用转换成Python能识别的对象,但它默认会用copy(复制)作为返回值策略——也就是尝试复制这个IFoo对象。

但IFoo是抽象类啊!抽象类根本不能实例化,自然也无法复制,所以直接触发了“type IFoo is non-copyable”的错误。

而你改成指针IFoo*时,pybind11默认会把指针包装成一个引用型的Python对象,不会尝试复制,所以就正常工作了。

怎么解决?

我们只需要告诉pybind11:这个IFoo&指向的对象是C++内部管理生命周期的,Python只需要临时用一下它的引用,不用复制。具体就是在绑定evaluate函数时,给回调参数指定reference_internal的返回值策略。

修改你的绑定代码如下:

PYBIND11_MODULE(libbindtest, module) {
    // 绑定抽象类IFoo(注意Python端命名为"Foo",这里可以根据需要改名,比如"IFoo"更清晰)
    py::class_<IFoo>(module, "Foo")
        .def("setValue", &IFoo::setValue);

    // 绑定evaluate函数,同时指定回调参数的返回值策略为reference_internal
    module.def("evaluate", &evaluate,
        py::return_value_policy::reference_internal);
}

如果你想更严谨地指定参数,可以用py::arg明确标注:

module.def("evaluate", &evaluate,
    py::arg("callback").policy(py::return_value_policy::reference_internal));

修改完后,你的Python代码就能正常运行了,执行后会输出22+34=56,完全符合预期。

额外补充

  • reference_internal策略的核心是:告诉pybind11,这个对象的生命周期由C全权管理,Python拿到的只是临时引用,不能在C对象销毁后继续使用(这里Foo实例在evaluate执行完就销毁,刚好匹配这个场景)。
  • 你当前把C的IFoo在Python端命名为Foo,虽然能跑,但容易和C的实现类Foo混淆,建议改成IFoo,可读性更好~

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.08 07:58:04