简体   繁体   English

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

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

In my C++ project I have a method which returns std::list<ModelComponent*>* , where ModelComponent is a custom class I've defined.在我的 C++ 项目中,我有一个返回std::list<ModelComponent*>*的方法,其中 ModelComponent 是我定义的自定义 class 。

My wrapper looks like this:我的包装看起来像这样:

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

When I try to use this method in Python I get the following error:当我尝试在 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.

If I do #include <pybind11/stl.h> in this file though, all sorts of errors are thrown during compilation, starting with:但是,如果我在此文件中执行#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:

This error seems to be thrown because of another class (which also has a wrapper) that defines typedef std::pair<ModelComponent*, unsigned int> Connection;这个错误似乎是因为另一个 class (它也有一个包装器)定义了typedef std::pair<ModelComponent*, unsigned int> Connection; (even though I ignore the methods returning this particular type). (即使我忽略了返回此特定类型的方法)。

I can't seem to find a way to get the method returning a std::list to work, the documentation says including pybind11/stl.h should do the trick, but for me it's only throwing more errors.我似乎找不到让返回std::list的方法工作的方法, 文档说包括pybind11/stl.h应该可以解决问题,但对我来说,它只会引发更多错误。

Edit: The code on which std::pair<ModelComponent*, unsigned int> is used is posted here: https://pastebin.com/AX2XBYEd编辑:使用std::pair<ModelComponent*, unsigned int>的代码发布在这里: https://pastebin.com/AX2XBYEd

The problem is your binding of std::list<Connection*>* getList() .问题是您对std::list<Connection*>* getList()的绑定。 SWIG doesn't know what to do with Connection* , only with Connection . SWIG 不知道如何处理Connection* ,只知道如何处理Connection You'll need to write a binding for Connection* .您需要为Connection*编写绑定。

In your pastebin code, you have:在您的 pastebin 代码中,您有:

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

replace that with:将其替换为:

template<typename T1, typename T2>
struct MyPair {
    T1 first;
    T2 second;
};

typedef MyPair<ModelComponent*, unsigned int> Connection;

while leaving the #include "pybind11/stl.h" in place should do the trick.#include "pybind11/stl.h"留在原处应该可以解决问题。

At issue is that none of the pre-provided specializations that were written for conversions match.问题在于,为转换编写的预先提供的专业化都不匹配。 You can of course also provide your own specialization.当然,您也可以提供自己的专业。

It's one of the reasons why in cppyy I prefer to leave objects as-is, and simply provide a pythonistic interface, and if you truly want a python object (a list as it may be here), it's trivially converted.这就是为什么在 cppyy 中我更喜欢让对象保持原样并简单地提供一个 Python 接口的原因之一,如果你真的想要一个 python object (可能是这里的列表),它的转换很简单。 Example below (I added inline definitions for class ConnectionManager to keep it simple; you hadn't any on pastebin), to compare:下面的示例(我添加了 class ConnectionManager 的内联定义以使其简单;您在 pastebin 上没有任何内容),以进行比较:

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

versus:相对:

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

And because of the pythonizations, it's a drop-in replacement in for-loops etc. as well (it implements the __iter__ protocol, for example).并且由于 Python 化,它也是 for 循环等中的替代品(例如,它实现了__iter__协议)。 Either which way, this approach certainly saves you from having to wade through those long C++ template error messages.无论哪种方式,这种方法肯定会让您不必费力地浏览那些冗长的 C++ 模板错误消息。 :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM