Cython:如何使用 C++ 类的用户定义转换?
Posted
技术标签:
【中文标题】Cython:如何使用 C++ 类的用户定义转换?【英文标题】:Cython: How user-defined conversion of C++-classes can be used? 【发布时间】:2019-12-30 23:13:09 【问题描述】:Cython 的 documentation 似乎对如何包装 user-defined conversion 保持沉默。
例如,当下面的 c++ 代码打印1
(即true
、here 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 使用用户定义的转换,如果不是,有什么解决方法?
【问题讨论】:
【参考方案1】:只看bool
案例:
我不相信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")
operator bool()
给出错误
'operator' 不是类型标识符
我假设它需要像所有其他 C++ 函数一样以返回类型开始(即 operator
没有特殊情况)。这行得通(有点……见下一点……):
bool operator bool()
这个语法就是tested for in Cython's testsuite。
但是,您确实需要在文件顶部执行 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()
。
简而言之:
-
使用
bint operator bool()
包装C++ 的operator bool()
不要为其他运算符包装和使用显式强制转换。
【讨论】:
以上是关于Cython:如何使用 C++ 类的用户定义转换?的主要内容,如果未能解决你的问题,请参考以下文章
如何从另一个包装的对象返回 Cython 中的包装 C++ 对象?
使用 Cython 时如何将一个 C++ 类(引用)传递给另一个?