【发布时间】:2020-04-23 10:16:19
【问题描述】:
我想在 cython 代码中使用 C++ std::priority_queue,其中每个项目都应该是结构或类,但我不知道如何定义比较器。
如果我考虑一个priority_queue,其中元素是标准类型,一切似乎都可以,如下例所示:
simple.pyx
# distutils: language = c++
cimport cython
from libcpp.queue cimport priority_queue
def testIntPriorityQueue():
cdef priority_queue[int] q
q.push(5)
q.push(15)
q.push(7)
print('q.top (after pushing 5, 15, 7) = ',q.top())
q.pop()
print('q.top (after popping one item) = ',q.top())
main.py
import simple
def main():
simple.testIntPriorityQueue()
main()
当我执行此代码时,priority_queue 在正确推送 5、15 和 7 后,最大的 (15) 位于顶部(因为它由 q.top 返回),并且在弹出一个元素 q.top 后返回 7 已成为去掉15后最大。
现在我希望有一个类似的行为,但将项目推入队列,不是标准类型的对象,而是更复杂的东西。
我尝试使用以下内容定义这样的结构:
simple.pxd
cimport cython
ctypedef struct myType:
int key
float a
float b
simple.pyx
# distutils: language = c++
cimport cython
from libc.stdlib cimport malloc, free
from libcpp.queue cimport priority_queue
from libcpp.vector cimport vector
def testPriorityQueue():
cdef myType * item
cdef priority_queue[myType*] q
item = <myType *> malloc(sizeof(myType))
item.key = 20
item.a = 3.
item.b = 4.
q.push(item)
item = <myType *> malloc(sizeof(myType))
item.key = 10
item.a = 1.
item.b = 2.
q.push(item)
item = q.top()
print('q.top',item.key,item.a,item.b)
现在编译器和运行时都没有提供错误,但是priority_queue中的排序当然不能定义,从打印中我得到顶部的项目是最后推送的。
在 C++ 中,为了让priority_queue 在这种情况下对推送的项目进行排序,应该提供一个比较方法作为队列实例化的参数,但是根据我的发现,这应该通过 less 的重载来完成运算符,如本 C++ 示例中所示:
struct ToastCompare
{
bool operator()(const Toast &t1, const Toast &t2) const
{
int t1value = t1.bread * 1000 + t1.butter;
int t2value = t2.bread * 1000 + t2.butter;
return t1value < t2value;
}
};
我尝试通过将这些行添加到 pyx 文件中来在 cython 中定义类似的函数:
simple.pyx
cdef extern from *:
"""
struct itemCompare{
bool operator() (self, myType *t1, myType *t2) const
{
return t1.key < t2.key;
}
};
"""
ctypedef struct itemCompare
cdef priority_queue[myType*,vector[myType*],itemCompare] q
但是在编译过程中我得到一个 “priority_queue 模板类型接收 1 个参数,得到 3 个” 错误。
是否可以在 cython 中将 C++ priority_queue 容器与自定义类对象一起使用?
尝试遵循@ead的建议,我尝试以这种方式修改代码:
simple.pyx
cdef extern from *:
"""
bool operator<(const myType t1, const myType t2)
{ return t1.key < t2.key;}
"""
def testPriorityQueue():
cdef priority_queue[myType*] q
离开simple.pxd
cimport cython
from libcpp cimport bool
ctypedef struct myType:
int key
float a
float b
但它无法编译捐赠:
simple.cpp:694:26: 错误:‘myType’没有命名类型 布尔运算符
所以我尝试在 C 逐字代码中移动结构定义并将其从 simple.pxd
中删除simple.pyx
def extern from *:
"""
typedef struct myType{
int key;
float a;
float b;
} myType;
bool operator<(const myType t1, const myType t2)
{return t1.key < t2.key;}
"""
ctypedef struct myType
def testPriorityQueue():
cdef myType * item
cdef priority_queue[myType*] q
item = <myType *> malloc(sizeof(myType))
现在编译错误是:
不能接受 sizeof 不完整类型 'myType'
如果我将结构定义也保留在 pxd 文件中,但从 pyx 中删除 ctypedef struct myType,则不会发生编译错误,但优先级队列不会对项目进行排序,就好像没有完成重载一样。
我的错误在哪里?
【问题讨论】:
-
打开这个问题需要一些时间 - 最好从头开始回答问题。
-
同时存在一些误解: 1) 你需要重写 operator less (stackoverflow.com/q/3006413/5769463) 而不是 operator()。 2)将您的对象本身而不是指针放入priority_queue(如果对象与您提供的一样小) - 内存管理没有问题(初学者更容易正确)。 3) 用 C++ 编写 struct + 运算符(您可以使用逐字 C 代码 (cython.readthedocs.io/en/latest/src/userguide/…) 并用 Cython 包装它 - 这比尝试在 Cython 中定义它们更容易。
-
感谢您的回答。这是我在这里的第一篇文章,所以我明白我必须在关闭后重新编辑它,而不是发布一个新问题。对不起
-
至于您的建议:1) 可以使用 less 运算符 2) 这只是一个示例,我需要放入优先级队列的对象比我在示例中使用的对象大,但我会尝试遵循您的建议 3)我已经尝试按照您的建议进行操作,但现在我的 pyx 的 cythonizing 停止并出现错误“priority_queue 模板类型接收 1 个参数,得到 3”所以我不知道它是否在 Cython 中是否限制 std:queue 的 C++ 包装
-
你可以用你当前的版本更新问题,因为没有看到代码就很难判断出了什么问题。
标签: containers cython