【发布时间】:2019-05-28 03:39:35
【问题描述】:
所以我正在使用 Cython 为 C++ 库编写 Python API。我有三个具有几乎相同功能的类:A、B 和 C。这种区别仅在于它们的对象之一是如何基于初始化和一些常量构建的。
最初,我将它们全部写成单独的类,然后可以在我的 cython 代码中通过 extern 定义它们。这编译并且运行良好,但是有很多重复的代码,我真的希望这个项目更加干燥。
所以我决定为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] *' 分配给 'BaseClass[T] *' Traceback(最近一次调用最后一次):文件“setup.py”, 第 9 行,在 setup(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) 文件“/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
有人知道怎么做吗?显然我的模板替换已关闭。我应该坚持使用重复的代码吗?还有其他聪明的解决方案吗?
【问题讨论】:
-
不确定你想要什么;你确定你不是在寻找 CRPT (Curiously recurring template pattern)?
-
你需要展示你的 cython 包装器,否则没人知道你的问题是什么,见minimal reproducible example。请确保您的示例是最小的 - 可能只有一个子类(而不是 3 个)足以显示问题。
-
我认为问题在于你实际上没有一个通用的基类——它们都有由模板生成的略有不同的基类,实际上很难为模板类创建好的 Cython 包装器没有重复。一种解决方案是generate the repetitive code。
-
这种方法行不通。在 C++ 中,从基类构造函数调用虚拟方法将不会在某些派生类中调用覆盖:它将调用虚拟方法的基类实现(如果存在)。
-
事实上,依赖虚拟方法使一个简单的需求复杂化。使用 T 参数定义 BaseClass 构造函数,并从派生类提供此参数(作为调用其自定义加载器方法的结果)。
标签: c++ templates cython template-specialization base-class