Wrapping C++ code with function pointer as template parameter in cython

巧了我就是萌 提交于 2021-02-05 08:18:45

问题


I am trying to wrap the following declaration written in C++ in cython:

template<typename T, double (*distance)(const DataPoint&, const DataPoint&)>
class VpTree
{...}

I've also got the following definition in C++:

inline double euclidean_distance(const DataPoint &t1, const DataPoint &t2) {...}

and I'm trying to wrap this in cython. This is what I've been able to come up with following the documentation:

cdef extern from "vptree.h":
    # declaration of DataPoint omitted here

    cdef inline double euclidean_distance(DataPoint&, DataPoint&)

    cdef cppclass VpTree[T, F]:  # F is almost certainly wrong
        ...

and build a wrapper around this:

cdef class VPTree:
    cdef VpTree[DataPoint, euclidean_distance] tree

    def __cinit__(self):
        self.tree = VpTree[DataPoint, euclidean_distance]()

Unfortunately, this results in the following errors:

------------------------------------------------------------

cdef class VPTree:
    cdef VpTree[DataPoint, euclidean_distance] tree
                                            ^
------------------------------------------------------------

unknown type in template argument

------------------------------------------------------------

cdef class VPTree:
    cdef VpTree[DataPoint, euclidean_distance] tree

    def __cinit__(self):
        self.tree = VpTree[DataPoint, euclidean_distance]()
                                     ^
------------------------------------------------------------

unknown type in template argument

I suspect the problem lies in the F part of the definition, and I've tried various things in place of that e.g. double(*)(DataPoint&, DataPoint&) but this obviously results in a syntax error.


回答1:


As far as I know, Cython doesn't support non-type template parameters (that is what function pointer is) directly (I might have missed the memo though), but there is a well known cname-hack to achieve the goal.

Here, for a much simpler example:

%%cython --cplus            
cdef extern from *:
    """
    template<int val>
    int fun(){return val;}
    """
    int fun[T]()

i.e. an int-value as template parameter.

Now we have a dilemma: Cython expects T to be type and g++ (or other compilers) expects an integer value - here comes the cname-hack to our rescue:

%%cython --cplus            
...
cdef extern from *:
    ctypedef int val2 "2" 

def doit():
    return fun[val2]()

Cython believes val2 to be a type (alias for int), but replaces it with 2 in the resulting c++ code (fun<2>()), thus c++-compiler sees an integer-value (2 in this case), as it expects.


For your case that means adding:

%%cython --cplus            
...
cdef extern from *:
    ctypedef int euclidean_distance_t "euclidean_distance" 

cdef class VPTree:
     cdef VpTree[DataPoint, euclidean_distance_t] tree

     def __cinit__(self):
         self.tree = VpTree[DataPoint, euclidean_distance_t]()

You actually don't have to wrap "euclidean_distance" at all, if you don't use it anywhere else in Cython code.



来源:https://stackoverflow.com/questions/53582945/wrapping-c-code-with-function-pointer-as-template-parameter-in-cython

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!