Доступ Pybind11 к непрозрачным векторам непрозрачных векторов - PullRequest
0 голосов
/ 28 июня 2019

Чтобы иметь возможность передавать векторы пользовательского типа по ссылке между Python и C ++, мой проект использует PYBIND11_MAKE_OPAQUE и pybind11::bind_vector<> для векторов моего типа. Однако , мне также нужно работать с вектором вектора моего пользовательского типа.Ниже приведен пример.

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/stl_bind.h>
#include <vector>

class Example {};

PYBIND11_MAKE_OPAQUE(std::vector<Example>);
PYBIND11_MAKE_OPAQUE(std::vector<std::vector<Example>>);

PYBIND11_MODULE(ExModule, m)
{
    pybind11::class_<Example>(m, "Example")
        .def(pybind11::init<>());

    pybind11::bind_vector<std::vector<Example>>(m, "ExampleVector");
    pybind11::bind_vector<std::vector<std::vector<Example>>>(m, "Example2DVector");
}

Если я создаю 2D-вектор моего типа в Python, а затем пытаюсь получить к нему доступ, я получаю ошибку.Ниже приведен пример кода Python.

from ExModule import Example, ExampleVector, Example2DVector

# a is a 10x10 vector of Examples
a = Example2DVector([ExampleVector([Example() for i in range(10)]) for i in range(10)])

b = a[4]

Сообщение об ошибке:

TypeError: Unable to convert function return value to a Python type! The signature was
    (self: ExModule.Example2DVector, arg0: int) -> std::vector<Example, std::allocator<Example> >

Вероятно, это связано с тем, что тип возвращаемого значения для операции индекса в 2D-векторном типе является непрозрачным.Я думаю, что должно произойти, возвращение должно быть построено в ExampleVector.Я не могу сделать это из Python, это должно быть сделано в модуле оболочки.Это ошибка или отсутствующая функция?Если нет, то как перегрузить оператор индекса в классе Example2DVector?

Ответы [ 2 ]

0 голосов
/ 30 июня 2019

Цитировать форму документов:

Этот макрос должен быть указан на верхнем уровне (и вне любых пространств имен), так как он создает частичную перегрузку шаблона. Если ваш код привязки состоит из нескольких модулей компиляции, он должен присутствовать в каждом файле (обычно через общий заголовок), предшествующий любому использованию std :: vector. Непрозрачные типы также должны иметь соответствующее объявление class_, чтобы связать их с именем в Python и определить набор доступных операций

@ ktb, это не ошибка, смотрите https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html?highlight=compilation%20unit#making-opaque-types

0 голосов
/ 28 июня 2019

Пример работает, но мой код - нет.Это было связано с тем, что в моем коде векторный класс 1D был связан с типом Python в другом модуле pybind11 .Таким образом, не было сопоставленного типа Python для одномерного векторного типа C ++, когда он определил __getitem__ для двумерного векторного класса.Тем не менее, я думаю, что если я импортирую модуль, содержащий 1D-векторную привязку Python, то он должен работать, но это не так.Это может быть ошибкой.

РЕДАКТИРОВАТЬ:

Это поведение не ошибка (я подумал, Якоб, кажется, довольно умный парень).Как обсуждено в руководстве по связыванию контейнеров STL, есть раздел о «локальных» привязках модуля.По умолчанию привязки типов являются локальными для модуля, в котором они определены, чтобы избежать нескольких разных привязок одного типа.

Однако наш проект содержит модуль «типы данных» и многие модули, использующие эти типы.В этом случае мы не хотим, чтобы типы данных, определенные в модуле «типы данных», были локальными.В противном случае мы столкнемся с проблемой возврата значений, не преобразуемых в правильный тип Python.

Мы можем отключить локальную привязку модуля по умолчанию в определении привязки.Используя пример вопроса, мы можем отключить локальную привязку модуля для ExampleVector, и доступ к Example2DVector (определенному в другом модуле) больше не будет давать сбой.

pybind11::bind_vector<std::vector<Example>>(m, "ExampleVector", pybind11::module_local(false));
...