Reputation: 34367
Cython's documentation seems to be silent about how user-defined conversion can be wrapped.
For example, while the following c++-code prints 1
(i.e. true
, here live):
#include <iostream>
struct X{
operator bool() const{ return true;}
};
int main() {
X x;
std::cout << x << "\n";
}
its "equivalent" in 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
doesn't get cythonized with the following error message (in the line marked with ERROR HERE
):
'operator' is not a type identifier
How user-defined conversion can be used from Cython and if not what are workarounds?
Upvotes: 1
Views: 709
Reputation: 34367
This are only some additions to DavidW's answer.
As already pointed out, only operator bool
is supported by Cython - other user-defined conversions, like:
cdef cppclass X:
int operator int()
will result in an error message like
Overloading operator 'int' not yet supported.
A possible workaround is not to wrap the user-defined conversion, but to use explicit cast whenever needed. For example:
%%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)
which compiles and prints 42
once testit
is called. Cython doesn't intervene with explicit cast here.
Ironically, the above workaround would not work for 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)
leads to error message:
Object of type 'X' has no attribute 'operator bool'
Obviously, this check is a part of the operator bool()
-support package..
One could however use cast to int
instead of cast to bool/bint
to achieve the goal:
...
if <int>x:
...
However, should wrapping the operator bool()
should be prefered.
In a nutshell:
bint operator bool()
to wrap C++'s operator bool()
Upvotes: 1
Reputation: 30917
Looking only at the bool
case:
I'm not convinced print(x)
should convert it to bool anyway. print(x)
looks for a conversion to a Python object (and OK, bool
can be converted to a Python object, but it's somewhat indirect). Python itself uses the __bool__
(__nonzero__
in Python 2) only in fairly limited circumstances, like in an if
statement, and Cython typically follows Python behaviour as a rule. Therefore I've changed the test-code to
def testit():
cdef X x
if x:
print("is True")
else:
print("if False")
operator bool()
gives the error
'operator' is not a type identifier
I assumed it needed to start with the return type like every other C++ function (i.e. no special case for operator
). This works (sort of... see next point...):
bool operator bool()
and this syntax is the one tested for in Cython's testsuite.
However, you do need to do from libcpp cimport bool
at the top of the file to get the C++ bool
type.
If you look at the converted source for if x:
it ends up as
__pyx_t_1 = __pyx_v_x.operator bool();
if (__pyx_t_1) {
operator bool
is called explicitly (which is pretty common for Cython), but is used in the correct place so Cython clearly understands what it's for. Similarly, if you do if x:
without defining the operator you get the error
Object of type 'X' has no attribute 'operator bool'
again, suggesting this is a feature of Cython.
There's clearly a bit of a documentation failure here, and I wouldn't be 100% surprised if the syntax changed to match C++ a bit closer in the future, maybe.
For the more general case: it looks like bool
is the only type-conversion operator supported at the moment, so you aren't able to define other operators.
Upvotes: 2