pybind11: невозможно получить std :: list для работы в Python - PullRequest
0 голосов
/ 03 ноября 2019

В моем проекте 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

Ответы [ 2 ]

0 голосов
/ 05 ноября 2019

В вашем коде для вставки:

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

замените его на:

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

typedef MyPair<ModelComponent*, unsigned int> Connection;

, оставив #include "pybind11/stl.h" на месте, чтобы добиться цели.

Проблема заключается в том, что ни одна из предварительно предоставленных специализаций, написанных для конверсий, не совпадает. Конечно, вы также можете предоставить свою собственную специализацию.

Это одна из причин, почему в cppyy я предпочитаю оставлять объекты как есть, и просто предоставлять интерфейс pythonistic, и если вы действительно хотите объект 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(_)
[]
>>> 

И из-заpythonizations, это также замена в циклах for и т. д. (например, он реализует протокол __iter__). В любом случае, этот подход, безусловно, избавляет вас от необходимости разбираться с этими длинными сообщениями об ошибках шаблона C ++. :)

0 голосов
/ 04 ноября 2019

Проблема в вашей привязке std::list<Connection*>* getList(). SWIG не знает, что делать с Connection*, только с Connection. Вам нужно написать привязку для Connection*.

...