Boost.Python 通过引用调用:TypeError:未找到C++类型的 to_python(按值)转换器

21 投票
1 回答
15122 浏览
提问于 2025-04-16 13:53

我正在尝试通过Boost.Python将我的C++类暴露给Python。下面是我想做的一个简化版本:

我有一个类A,它是从boost::noncopyable派生的,还有一个类B,里面有一个方法,这个方法需要一个A类的引用作为参数。

class A : boost::noncopyable { /*...*/ };

class B {

public:

    virtual void do_something(A& a) {
        /*...*/
    }
};

我这样暴露这些类:

/* Wrapper for B, so B can be extended in python */
struct BWrap : public B, wrapper<B> {

    void do_something(A &a) {

        if (override do_something = this->get_override("do_something")) {
            do_something(a);
            return;
        }
        else {
            B::do_something(a);
        }
    }

    void default_do_something(A& a) { this->B::do_something(a); }
};

BOOST_PYTHON_MODULE(SomeModule) {

    class_<A, boost::noncopyable>("A");

    class_<BWrap, boost::noncopyable>("B")
        .def("do_something", &B::do_something, &BWrap::default_do_something)
    ;
}

我在Python中扩展B,方法如下:

test.py:

import SomeModule


class BDerived(SomeModule.B):

    def do_something(self, a):
        pass

然后我这样调用扩展后的B:

try {
    py::object main = py::import("__main__"); \
    py::object global(main.attr("__dict__")); \
    py::object result = py::exec_file("test.py", global, global); \
    py::object pluginClass = global["BDerived"]; \
    py::object plugin_base = pluginClass(); \

    B& plugin = py::extract<B&>(plugin_base) BOOST_EXTRACT_WORKAROUND;

    A a;
    B.do_something(a);
}
catch (py::error_already_set) { 
    PyErr_Print();
}

但是这导致出现了一个错误信息:

TypeError: No to_python (by-value) converter found for C++ type: A

如果A没有从boost::noncopyable派生,代码就能正常运行,但在调用do_something(A& a)时,参数a会被复制,尽管它是通过引用传递的。不过,简单地去掉A的noncopyable要求并不是一个选项,因为这样做是有原因的。

有没有什么建议可以解决这个问题?

谢谢。

1 个回答

20

B.do_something(a); 改成 B.do_something(boost::ref(a));

可以查看 Boost手册中的调用Python函数和方法

撰写回答