This is similar to this question, but it never got any solutions, and I have at least a workaround for the problem, as inelegant as it is.
I am trying to wrap a templated class, Point<_T,__Scale>
, where _T=int,float...
and __Scale
is an int. Now the compiler will generate a separate class for each template value used, but the classes are not related in any way. However, the classes share all their methods, mostly operator overloads for !=<>*&/|
, and getters.
In Cython, the only way I have been able to wrap Point<_T,__Scale>
is to provide a cdef class for each variation. It works, but results in a lot of copy-pasted code. I would like to know if there is way to share the code between these template class wrappers. Note that I am following the cython method for wrapping described in the tutorials, where a wrapper class holds a *thisptr
to the c-object it is wrapping.
// c++ header
template<_T,__Scale>
class Point
{
Point(_T _x, _T _y) : x(_x), y(_y) {};
// copy constructor
template<typename _NT> Point(const Point<_NT, __Scale> &pt) : x( (_T)pt.x ), y( (_T)pt.y ) {};
_t x, y;
bool operator == (const Point<_T,__Scale> &pos) const
bool operator != (const Point<_T,__Scale> &pos) const
// and many more operators
}
typedef Point<int,1> PointA
typedef Point<int,8> PointB
... //additional typedefs
# cython interface with c++ (not shown: cdef extern from ...)
cdef cppclass Point[_T,__Scale]:
Point(_T _x, _T _y)
Point[_NT] Point(const Point[_NT,0] &pt)
_T x
_T y
bint operator == (const Point[_T,__Scale] &pos) const
bint operator != (const Point[_T,__Scale] &pos) const
# cython wrapper to interface with python (this is where it gets messy)
cdef class pyPointA:
cdef PointA* thisptr
def __cinit__(self, int x, int y):
self.thisptr = new PointA(x,y)
# everything in this class below this line is copied
def x(self, setX = None):
if(setX is None):
return self.thisptr.x
else:
self.thisptr.x = setX
def y(self, setY = None):
if(setY is None):
return self.thisptr.y
else:
self.thisptr.y = setY
# and many more operators
cdef class pyPointB
cdef PointB* thisptr
def __cinit__(self, int x, int y):
self.thisptr = new PointB(x,y)
# everything in this class below this line is copied
def x(self, setX = None):
if(setX is None):
return self.thisptr.x
else:
self.thisptr.x = setX
def y(self, setY = None):
if(setY is None):
return self.thisptr.y
else:
self.thisptr.y = setY
# and many more operators
...
#continue for additional point types
Here is what I have tried:
- Abstract cython base class to inherit the others from. Ok, but each template type needs different pointers.
- Store
*thisptr
as*void
. How to deal with the casting? - encapsulate
thisptr
by retrieving it using a gettergetPtr()
, but still am forced into a single return type. Cannot declare as Python function, because c pointers cannot be wrapped in python objects. - write several method that return the correct pointer type, then the
getPtr()
method returns the right getter for each method to call, to get the pointer from. Unfortunately, only c-functions can return pointers, and they cannot be returned: compiler complains 'not found'. - Same as above, except the
getPtr()
method returns the string name of the getter function, which then we can usegetattr()
to recall. But cdef method is unable to be found in Python usinggetattr()
.