pybind11:无法让 std::list 在 Python 中工作

pybind11: Can't get std::list to work in Python

本文关键字:Python 工作 list std pybind11      更新时间:2023-10-16

在我的C++项目中,我有一个返回std::list<ModelComponent*>*的方法,其中ModelComponent是我定义的自定义类。

我的包装看起来像这样:

py::class_<ComponentManager>(m, "ComponentManager")
.def(py::init<Model*>())
.def("getAllComponents", &ComponentManager::getAllComponents,
py::return_value_policy::reference);

当我尝试在Python中使用此方法时,我会得到以下错误:

TypeError: Unable to convert function return value to a Python type! The signature was
(self: libgenesys.ComponentManager) -> std::__cxx11::list<ModelComponent*, std::allocator<ModelComponent*> >
Did you forget to `#include <pybind11/stl.h>`? Or <pybind11/complex.h>,
<pybind11/functional.h>, <pybind11/chrono.h>, etc. Some automatic
conversions are optional and require extra headers to be included
when compiling your pybind11 module.

如果我在这个文件中执行#include <pybind11/stl.h>,那么在编译过程中会抛出各种错误,从开始

/usr/include/pybind11/cast.h:1408:73: error: no matching function for call to ‘get<0>(std::pair<ModelComponent*, unsigned int>*&)’
In file included from /usr/include/c++/9.2.0/bits/unique_ptr.h:36,
from /usr/include/c++/9.2.0/memory:80,
from /usr/include/c++/9.2.0/thread:39,
from main.cpp:15:

这个错误似乎是因为另一个类(它也有一个包装器(定义了typedef std::pair<ModelComponent*, unsigned int> Connection;而抛出的(尽管我忽略了返回这个特定类型的方法(。

我似乎找不到让返回std::list的方法工作的方法,文档说包括pybind11/stl.h应该可以,但对我来说,这只会带来更多的错误。

编辑:使用std::pair<ModelComponent*, unsigned int>的代码发布在此处:https://pastebin.com/AX2XBYEd

问题在于您对std::list<Connection*>* getList()的绑定。SWIG不知道该如何处理Connection*,只知道该如何使用Connection。您需要为Connection*编写一个绑定。

在您的pastebin代码中,您有:

typedef std::pair<ModelComponent*, unsigned int> Connection;

替换为:

template<typename T1, typename T2>
struct MyPair {
T1 first;
T2 second;
};
typedef MyPair<ModelComponent*, unsigned int> Connection;

而将CCD_ 11留在适当的位置就可以了。

争论的焦点是,为转换而编写的预先提供的专业化都不匹配。当然,你也可以提供自己的专业。

这就是为什么在cppyy中,我更喜欢保持对象原样,只提供一个python接口的原因之一,如果你真的想要一个python对象(这里可能是一个列表(,它会被简单地转换。下面的示例(我为ConnectionManager类添加了内联定义以保持简单;您在pastebin上没有任何定义(,以进行比较:

>>> import ConnectionManager
>>> cm = ConnectionManager.ConnectionManager()
>>> cm.getList()
[]
>>>

对比:

>>> import cppyy
>>> cppyy.include("ConnectionManager.h")
>>> cm = cppyy.gbl.ConnectionManager()
>>> cm.getList()
<cppyy.gbl.std.list<pair<ModelComponent*,unsigned int>*> object at 0x7faa345759c0>
>>> list(_)
[]
>>> 

由于Python化,它也是循环等的替代品(例如,它实现了__iter__协议(。无论哪种方式,这种方法都可以使您不必费力地处理那些冗长的C++模板错误消息。:(