Cython:如何使用 C++-类 的用户自定义转换?

Cython: How user-defined conversion of C++-classes can be used?

Cython 的 documentation seems to be silent about how user-defined conversion 可以被包装。

例如,当以下 c++ 代码打印 1(即 truehere live)时:

#include <iostream>

struct X{
    operator bool() const{ return true;}    
};

int main() {
    X x;
    std::cout << x << "\n";
}

其在 Cython 中的 "equivalent":

%%cython  -+
cdef extern from *:
    """
    struct X {
        //implicit conversion
        operator bool() const { return true; }
    };
    """
    cdef cppclass X:
        operator bool()  # ERROR HERE

def testit():
    cdef X x;
    print(x) # implicit cast, "should" print True

没有被 cythonized 并出现以下错误消息(在标有 ERROR HERE 的行中):

'operator' is not a type identifier

如何从 Cython 使用用户定义的转换,如果不能,有什么解决方法?

仅查看 bool 案例:

  1. 我不相信 print(x) 应该将它转换为布尔值。 print(x) 查找到 Python 对象的转换(好吧,bool 可以转换为 Python 对象,但有点间接)。 Python 本身仅在相当有限的情况下使用 __bool____nonzero__ in Python 2),例如在 if 语句中,而 Cython 通常遵循 Python 作为规则的行为。因此我将测试代码更改为

    def testit():
        cdef X x
        if x:
            print("is True")
        else:
            print("if False")
    
  2. operator bool()给出错误

    'operator' is not a type identifier

    我假设它需要像所有其他 C++ 函数一样以 return 类型开始(即 operator 没有特殊情况)。这有效(有点......见下一点......):

    bool operator bool()
    

    这个语法就是 tested for in Cython's testsuite.

  3. 但是,您确实需要在文件顶部执行 from libcpp cimport bool 以获得 C++ bool 类型。

如果您查看 if x: 的转换源,它最终会变成

__pyx_t_1 = __pyx_v_x.operator bool();
if (__pyx_t_1) {

operator bool 被显式调用(这对于 Cython 来说很常见),但在正确的位置使用,因此 Cython 清楚地理解它的用途。同样,如果你在没有定义运算符的情况下执行 if x:,你会得到错误

Object of type 'X' has no attribute 'operator bool'

再次表明这是 Cython 的一个特性。

这里显然有一点文档错误,如果将来语法更改为更接近 C++,我不会 100% 感到惊讶。


对于更一般的情况:it looks like bool is the only type-conversion operator supported 目前,您无法定义其他运算符。

这只是对 的一些补充。

如前所述,Cython 仅支持 operator bool - 其他用户定义的转换,例如:

cdef cppclass X:
    int operator int()

将导致类似

的错误消息

Overloading operator 'int' not yet supported.

一种可能的解决方法是不包装用户定义的转换,而是在需要时使用显式转换。例如:

%%cython  -+ -a
cdef extern from *:
    """
    struct X {
        //implicit conversion
        operator int() const { return 42; }
    };
    """
    cdef cppclass X:
        pass # leave operator int() out

def testit():
    cdef X x;
    print(<int>x)

一旦调用 testit 就会编译并打印 42 。 Cython 不干预此处的显式转换。

具有讽刺意味的是,上述解决方法不适用于 operator bool():

%%cython  -+ -a
cdef extern from *:
    """
    struct X {
        //implicit conversion
        operator bool() const { return true; }
    };
    """
    cdef cppclass X:
        pass # leave operator bool() out

def testit():
    cdef X x;
    if <bint>x:
       print(True)
    else:
       print(False)

导致错误信息:

Object of type 'X' has no attribute 'operator bool'

显然,此检查是 operator bool()-支持包的一部分..

然而,可以使用转换为 int 而不是转换为 bool/bint 来实现目标:

...
if <int>x:
...

但是,应该首选 operator bool() 包装。


简而言之:

  1. 使用 bint operator bool() 包装 C++ 的 operator bool()
  2. 不要为其他运算符包装和使用显式转换。