Как обернуть структуру C ++ в Cython для вызова конструктора C ++? - PullRequest
0 голосов
/ 26 апреля 2020

Я новичок в интерфейсе Cython / C ++ и в настоящее время изучаю примеры в документации. Я пытаюсь найти способ обернуть структуру C ++ (вместо собственных типов C / C ++), которая используется в качестве спецификатора типа аргумента конструктора класса C ++. Затем я могу создать экземпляр класса C ++ на стороне Python.

Во-первых, файл rectangle.cpp, который является упрощенной версией примера только с конструкторами. Здесь я представлю структуру, которая будет использоваться в качестве типа аргумента для конструктора. (Я объединил заголовочный файл .h с .cpp только для того, чтобы сделать сообщение короче. Хотя это обычно компилируется.)

прямоугольник. cpp

#include <iostream>

namespace shapes {

    struct Point {
        int x0;
        int y0;
        int x1;
        int y1;
    };

    class Rectangle {
        public:
            int x0, y0, x1, y1;
            Rectangle();
            Rectangle(Point point);
            ~Rectangle();
    };

    // Default constructor
    Rectangle::Rectangle () {}

    Rectangle::Rectangle (Point point) {
        this->x0 = point.x0;
        this->y0 = point.y0;
        this->x1 = point.x1;
        this->y1 = point.y1;
    }

    // Destructor
    Rectangle::~Rectangle () {}
}

Во-вторых, файл rectangle.pxd, который в основном является копией из примера, за исключением того, что я включил cdef struct Point для объявления структуры. ( Не уверен, что это правильный подход. )

rectangle.pxd

# Declare the class with cdef
cdef extern from "rectangle.cpp" namespace "shapes":
    cdef struct Point:
        int x0
        int y0
        int x1
        int y1 

    cdef cppclass Rectangle:
        Rectangle() except +
        Rectangle(Point) except + # Not sure if this is correct
        int x0, y0, x1, y1

В-третьих, rect.pyx файл

rect.pyx

# distutils: language = c++

from rectangle cimport Rectangle, Point

# Create a Cython extension type which holds a C++ instance
# as an attribute and create a bunch of forwarding methods
# Python extension type.
cdef class PyRectangle:
    cdef Point point # Not sure if this is correct

    cdef Rectangle c_rect  # Hold a C++ instance which we're wrapping

    def __cinit__(self, Point point):
        self.c_rect = Rectangle(point)    

Наконец, setup.py, что идентично примеру.

setup.py

from setuptools import setup

from Cython.Build import cythonize

setup(ext_modules=cythonize("rect.pyx"))

Если я скомпилирую стандартную команду python3 setup.py build_ext --inplace, появится следующая ошибка. (Исходный пример можно без проблем скомпилировать и запустить.)

[1/1] Cythonizing rect.pyx

Error compiling Cython file:
------------------------------------------------------------
...
    PyTypeObject *Py_TYPE(obj)
    bint PyMapping_Check(obj)
    object PyErr_Format(exc, const char *format, ...)

@cname("__pyx_convert__from_py_shapes::Point")
cdef Point __pyx_convert__from_py_shapes::Point(obj) except *:
                                        ^
------------------------------------------------------------

FromPyStructUtility:11:41: Expected an identifier or literal
Traceback (most recent call last):
  File "setup.py", line 5, in <module>
    setup(ext_modules=cythonize("rect.pyx"))
  File "/usr/lib/python3/dist-packages/Cython/Build/Dependencies.py", line 877, in cythonize
    cythonize_one(*args)
  File "/usr/lib/python3/dist-packages/Cython/Build/Dependencies.py", line 997, in cythonize_one
    raise CompileError(None, pyx_file)
Cython.Compiler.Errors.CompileError: rect.pyx

Я уверен, что при переносе структуры есть ошибки, так как ошибка вызывается FromPyStructUtility. Но я не нашел прямого ответа / решения для этого конкретного сценария. Если я хочу сохранить код C ++ как есть, то есть настаивать на передаче структуры конструктору, как мне реализовать это на стороне Cython? Ваши комментарии / предложения / учебники будут высоко оценены.

...