在Cython中是否会破坏非成员运算符重载(特别是运算符==)?

时间:2018-03-28 01:11:40

标签: python c++ python-3.x operator-overloading cython

我有一个用例我正在测试哪里,为了性能,为C ++的unordered_map<int, int>类型预先编写一个Cython包装类很方便,然后将包装器传递给一堆使用的Cython函数它,而不是总是传递Python dict(由C int的Python int键入和估值)并一遍又一遍地转换。我也尝试烘焙一些基本功能,使其在Python层的行为类似于dict,因此无需将整体从Python dict转换为Cython {{1}包裹和回来。

在最简单的情况下(将一个包装器实例与另一个包装器实例进行比较)尝试有效地实现unordered_map<int, int>时出现问题。 AFAICT,而Cython的__eq__ libcpp.unordered_map定义假装pxd有一个成员unordered_mapThis answer声称它应该没问题,即使operator==实际上是一个非成员函数,因为定义只需要存在,所以Cython知道它可以只放一个文字operator==码;编译扩展模块时,C ++编译器会查找真正的重载。

但在实践中,如果没有额外的手动(和hacky)干预,我似乎无法让它工作。对于实验,我刚刚使用== ipython魔法。现在我正在做的是(尽可能减少,同时仍然出现问题):

%%cython

要明确,这现在可行,例如:

>>> %load_ext cython
>>> %%cython -+ --verbose --compile-args=/std:c++latest
... from libcpp.unordered_map cimport unordered_map
... from cython.operator cimport dereference as deref
... cdef extern from "<unordered_map>" namespace "std":
...     bint operator==(unordered_map[int, int]&, unordered_map[int, int]&)
... cdef class UII(object):
...     cdef unordered_map[int, int] c_map
...     def __cinit__(self, dict py_map):
...         cdef int k, v
...         for k, v in py_map.iteritems():
...             self.c_map[k] = v
...     def __eq__(UII self, other):
...         if isinstance(other, UII):
...             return self.c_map == (<UII>other).c_map
...         return NotImplemented
...

有效,因为我包括:

>>> pydict = {1:2, 3:4}; ui = UII(pydict); uieq = UII(pydict); uine = UII({1: 2, 4: 3})
>>> ui == uieq   # Compares equal for same value UIIs
True
>>> ui == uine   # Correctly determines different valued UII not-equal
False

专门为cdef extern from "<unordered_map>" namespace "std": bint operator==(unordered_map[int, int]&, unordered_map[int, int]&) 模板明确定义operator==的非成员重载(因为Cython不支持通用模板化函数,只支持通用模板化类和显式声明的函数模板)。如果我省略这些行,我从Cython中得到以下错误:

<int, int>

表示它认为[1/1] Cythonizing C:\Users\ShadowRanger\.ipython\cython\_cython_magic_ea9bfadf105ac88c17e000476fd582dc.pyx Error compiling Cython file: ------------------------------------------------------------ ... cdef int k, v for k, v in py_map.iteritems(): self.c_map[k] = v def __eq__(UII self, other): if isinstance(other, UII): return self.c_map == (<UII>other).c_map ^ ------------------------------------------------------------ C:\Users\ShadowRanger\.ipython\cython\_cython_magic_ea9bfadf105ac88c17e000476fd582dc.pyx:13:30: Invalid types for '==' (unordered_map[int,int], unordered_map[int,int]) 没有超载可用。我做错了什么我可以解决,或者是非成员operator==(以及可能的其他非成员函数,尽管有this answer claims)的Cython被破坏了?我讨厌明确定义非成员函数的每个模板专门化;对于这个特定情况来说,这不是一个巨大的负担,但Cython会定义成员重载似乎很奇怪,可能是为了解决这个特定问题,但实际上并不能使用它们。我检查了operator==的实际文本,它在那里明确定义:

unordered_map.pxd

1 个答案:

答案 0 :(得分:1)

有关Cython处理非成员运营商的两件事情已经破裂:

  1. 在课堂外的.pxd文件中定义的非成员运算符不能正确CREATE PROCEDURE ReturnValue @ColumnName VARCHAR(250), @ColumnValue VARCHAR(250) AS DECLARE @Result VARCHAR(250) EXEC @Result = GetValue @ColumnName, @ColumnValue -- EXEC ReturnValue 'MobileNo', '+8801919111333' 到Cython(工作区要做cimport)因此不是&#39 ;使用。这就是我想我在previous answer

  2. 中所说的话
  3. 在具有两个参数的类中定义的非成员运算符(如在unordered_map.pxd中显示的代码中)未被Cython识别且未被使用(尽管是定义类似于Cython中包含的所有C ++标准库包装器。有一次,我试图为此提交一个补丁,但它被忽略了。

  4. 告诉Cython它是一个成员运算符(即使C ++将它作为非成员运算符实现)也是有用的。因此,unordered_map.pxd的简单补丁可以正常工作。 请注意,我将其更改为使用一个参数和C ++隐式from something cimport * / this 进行定义:

    self

    或者,您可以在需要使用它之前自己定义它(就像您当前正在做的那样),但作为模板。这至少可以节省您必须定义每个专业化

    cdef extern from "<unordered_map>" namespace "std" nogil:
        cdef cppclass unordered_map[T, U]:
            # ... irrelevant stuff expunged ...
            bint operator==(unordered_map&)
    

    即。你问题中的陈述

      

    (因为Cython不支持通用模板化函数,只支持通用模板化类和显式声明函数模板)

    不是真的。

    虽然

    ,但这有点乱