python — перенос типов возвращаемых контейнеров STL с использованием Pybind11

Я пытаюсь обернуть функцию C ++ (используя Pybind11), которая возвращает контейнер STL, который сам заключен в умный указатель. Пример показан ниже. Функция перегружена, поэтому я должен указать подпись.

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include "my_class.h"
typedef std::array<std::complex<double>, 4> ArrayComplex4;
PYBIND11_MAKE_OPAQUE(ArrayComplex4);

namespace py = pybind11;
using namespace my_namespace;

PYBIND11_MODULE(my_module, m) {
py::class_<MyClass>(m, "MyClass", py::dynamic_attr())
.def("my_function", (std::unique_ptr<ArrayComplex4> (MyClass::*)(double)) &MyClass::my_function)
.def("my_function", (std::unique_ptr<ArrayComplex4> (MyClass::*)(double, double)) &MyClass::my_function);
}

Модуль скомпилируется, но выдает ошибку, когда я пытаюсь использовать функцию в Python:

TypeError: Невозможно преобразовать возвращаемое значение функции в тип Python!

Я уверен, что просто настраиваю что-то не так для Pybind11. Спасибо за любую помощь!

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

Проблема была определенно в моей попытке связать std::Array тип данных. В итоге я изменил код для использования std::Vector и тогда у Pybind11 не было проблем. Смотрите ответ А.С. Макки ниже о том, как можно связать std::Array контейнеры.

1

Решение

Проблема может быть связана с обработкой PYBIND11_MAKE_OPAQUE структуры данных ArrayComplex4, я не мог заставить это работать, хотя я посмотрю на это еще немного, когда у меня будет время.

Следующий код, который я получил, является моим самым близким приближением к вашему дизайну. Я использовал дополнительную пользовательскую структуру данных, чтобы обернуть элементы std :::

#include <pybind11/pybind11.h>
#include <pybind11/complex.h>
#include <pybind11/stl.h>
#include <memory>
#include <complex>
#include <array>
#include <cmath>

namespace py = pybind11;typedef std::array<std::complex<double>, 4> ArrayComplex4;

struct ArrayComplex4Holder
{
ArrayComplex4 data;
ArrayComplex4 getData() { return data; }
};

class MyClass {
public:
MyClass() { }
std::unique_ptr<ArrayComplex4Holder> my_function(double x)
{
std::unique_ptr<ArrayComplex4Holder> ph( new ArrayComplex4Holder());
ph->data[0] = std::complex<double>(x);
return ph;
}
std::unique_ptr<ArrayComplex4Holder> my_function(double x, double y)
{
std::unique_ptr<ArrayComplex4Holder> ph( new ArrayComplex4Holder());
ph->data[0] = std::complex<double>(x);
ph->data[1] = std::complex<double>(y);
return ph;
}
};

PYBIND11_MODULE(example, m) {
m.doc() = "pybind11 example"; // optional module docstring

py::class_<ArrayComplex4Holder>(m, "ArrayComplex4Holder")
.def(py::init<>())
.def("getData", &ArrayComplex4Holder::getData);

py::class_<MyClass>(m, "MyClass")
.def(py::init<>())
.def("my_function", (std::unique_ptr<ArrayComplex4Holder> (MyClass::*)(double))         &MyClass::my_function)
.def("my_function", (std::unique_ptr<ArrayComplex4Holder> (MyClass::*)(double, double)) &MyClass::my_function);
}

NB Я обнаружил, что дополнительный pybind #include был необходим для того, чтобы заставить работать питона.

Простой код Python:

import sys
sys.path.append('/Volumes/RAID 1/Projects/workspace/Project CPP 1')
import example

p = example.MyClass()
print (p.my_function(1.2345).getData())
print (p.my_function(1.2345, 6.7890).getData())

Это приводит к следующему выводу, который выглядит правильно:

[(1.2345+0j), 0j, 0j, 0j]
[(1.2345+0j), (6.789+0j), 0j, 0j]

Я надеюсь, что это дает вам отправную точку для работы. Мне было бы интересно узнать, если вы найдете лучшую альтернативу … С уважением, AS

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]