【问题标题】:using C++ containers in cython在 cython 中使用 C++ 容器
【发布时间】: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


【解决方案1】:

我的问题的答案是使用以下 pxd 文件:

cimport cython
from libcpp cimport bool

cdef extern from *:
    """
    typedef struct {
        int key;
        float a;
        float b;       
    } myType;

    bool operator<(const myType t1, const myType t2) {
        return t1.key < t2.key;
    }
    """
    ctypedef struct myType:
        int key
        float a
        float b

感谢@ead 的帮助

【讨论】:

    猜你喜欢
    • 2013-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-08
    • 2019-12-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多