在Cython中优雅地包装模板化对象

时间:2014-03-24 00:56:52

标签: c++ templates pointers dry cython

这与this question,类似,但它从来没有得到任何解决方案,而且我至少有一个解决方法,因为它不够优雅。

我正在尝试包装一个模板化的类Point<_T,__Scale>,其中_T=int,float...__Scale是一个int。现在,编译器将为使用的每个模板值生成一个单独的类,但这些类不以任何方式相关。但是,这些类共享所有方法,主要是!=<>*&/|的运算符重载和getter。

在Cython中,我能够包装Point<_T,__Scale>的唯一方法是为每个变体提供一个cdef类。它可以工作,但会产生大量的复制粘贴代码。我想知道是否有办法在这些模板类包装器之间共享代码。请注意,我遵循教程中描述的包装的cython方法,其中包装类将*thisptr保存到它正在包装的c对象。

// 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

以下是我的尝试:

  • 摘要cython基类继承其他人。好的,但每种模板类型都需要不同的指针。
  • *thisptr存储为*void。如何处理铸造?
  • 通过使用getter thisptr检索它来封装getPtr(),但仍然被强制转换为单个返回类型。不能声明为Python函数,因为c指针不能包装在python对象中。
  • 编写几个返回正确指针类型的方法,然后getPtr()方法为每个要调用的方法返回正确的getter,以获取指针。不幸的是,只有c函数可以返回指针,并且无法返回它们:编译器抱怨'找不到'。
  • 与上面相同,除了getPtr()方法返回getter函数的字符串名称,然后我们可以使用getattr()来回忆。但是使用getattr()无法在Python中找到cdef方法。

1 个答案:

答案 0 :(得分:1)

这方面的困难在于模板需要在C编译时实例化......当然在C ++中,各种模板实例化没有共同的“超类”。

通常我建议在这种情况下使用模板引擎(如jinja2)来生成您感兴趣的所有类的排列。