Обтекание дочерних классов шаблонного базового класса в Cython - PullRequest
0 голосов
/ 31 декабря 2018

Итак, я пишу Python API для библиотеки C ++, используя Cython.У меня есть три класса с почти идентичной функциональностью: A, B и C.Эта разница заключается только в том, как один из их объектов построен на инициализации и некоторых константах.

Первоначально я записал их все как отдельные классы, а затем смог определить их через extern в моем коде Cython.Это компилируется и работает хорошо, но много повторяющегося кода, и мне бы очень хотелось, чтобы этот проект был более СУХИМ.

Поэтому я решил написать базовый класс для A, B и C, который реализовал большую часть функциональности один раз.Однако мне нужно было создать шаблон этого базового класса, и это вызывает у меня кошмар, когда я пытаюсь все определить в Cython.Вот игрушечный пример того, о чем я говорю (не обращайте внимания на пропущенные точки с запятой и т. Д., Если вы их найдете).Это мой файл "classes.h"

int library_method_load(std::string file_name){
    return std::string.length();
}

template <class T>
class BaseClass{
public:
    T important_obj;
    BaseClass(std::string file_name){ important_obj = library_method(file_name);};
    virtual T library_method(std::string file_name) = 0;
    // Important logicks...
    ~BaseClass(){};
}



class A : public BaseClass<int> {
    A(std::string file_name): BaseClass<int>(file_name){};
    int library_method(std::string file_name){ return library_method_load(file_name);};
    ~A(){};
}

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

Вот моя текущая попытка

#distutils: language = c++
from libcpp.string cimport string

cdef extern from "classes.h":
    cppclass BaseClass[T]:
        BaseClass(string file_name)

cdef extern from "classes.h":
    cppclass A(BaseClass[int]):
        A(string file_name)

cdef class PyBase:
    cdef BaseClass* wrapped

cdef class PyA(PyBase):
    def __cinit__(self, string file_name):
        self.wrapped = <BaseClass[int]*> new A(file_name)

При этом возникает следующая ошибка компилятора:

Ошибка компиляции файла Cython: ------------------------------------------------------------ ...

cdef класс PyA (PyBase):

def __cinit__(self, string file_name):
    self.wrapped = <BaseClass[int]*> new A(file_name)

^

wrapper.pyx: 23: 23: Невозможно назначить тип 'BaseClass [int] * 'to' BaseClass [T] * 'Traceback (последний вызов был последним): файл "setup.py", строка 9, в настройке (name = "test", version = "1.0.0", ext_modules = cythonize ([rk])) Файл "/home/jacob/anaconda3/lib/python3.6/site-packages/Cython/Build/Dependencies.py", строка 1027, в cythonize cythonize_one (* args) File "/ home / jacob /anaconda3 / lib / python3.6 / site-packages / Cython / Build / Dependencies.py ", строка 1149, в cythonize_one повысить CompileError (None, pyx_file) Cython.Compiler.Errors.CompileError: wrapper.pyx

Кто-нибудь знает, как это сделать?Очевидно, моя замена шаблона отключена.Должен ли я придерживаться повторяющегося кода вместо этого?Есть ли другие умные решения?

1 Ответ

0 голосов
/ 02 января 2019

Одним из решений является отбрасывание PyBase, поскольку в cdef BaseClass* wrapped отсутствует аргумент шаблона для BaseClass, что делает строку бессмысленной.

Например:

cdef class PyA(PyBase):
    cdef A* wrapped
    def __cinit__(self, string file_name):
        self.wrapped = new A(file_name)

(хотя я не уверен, что вы можете передать объект C ++ в __init__ и __cinit__)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...