问题
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