【问题标题】:Cython: How user-defined conversion of C++-classes can be used?Cython:如何使用 C++ 类的用户定义转换?
【发布时间】:2019-12-30 23:13:09
【问题描述】:

Cython 的 documentation 似乎对如何包装 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 中的“等价物”:

%%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' 不是类型标识符

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

【问题讨论】:

    标签: python c++ cython


    【解决方案1】:

    只看bool案例:

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

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

      'operator' 不是类型标识符

      我假设它需要像所有其他 C++ 函数一样以返回类型开始(即 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:,则会收到错误

    “X”类型的对象没有属性“operator bool”

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

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


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

    【讨论】:

    • 你可能是对的,期望转换为 python 对象太多了。
    • C++ 对自动使用转换运算符有点过于急切,因此通常最好使用 explicit 运算符来避免这种情况。 Cython 不会尝试自动执行此操作可能是明智的。
    【解决方案2】:

    这只是对DavidW's answer 的一些补充。

    正如已经指出的,Cython 仅支持 operator bool - 其他用户定义的转换,例如:

    cdef cppclass X:
        int operator int()
    

    将导致类似的错误消息

    尚不支持重载运算符“int”。

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

    %%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)
    

    导致错误信息:

    “X”类型的对象没有属性“operator bool”

    显然,此检查是 operator bool()-support 包的一部分。

    但是,可以使用 cast to int 而不是 cast to bool/bint 来实现目标:

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

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


    简而言之:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-10
      • 2011-04-02
      • 1970-01-01
      • 1970-01-01
      • 2013-02-24
      • 1970-01-01
      • 2018-05-20
      相关资源
      最近更新 更多