简体   繁体   English

在cython中使用函数指针作为模板参数包装C ++代码

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

I am trying to wrap the following declaration written in C++ in cython: 我试图在cython中包装以下用C ++编写的声明:

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

I've also got the following definition in C++: 我在C ++中也有以下定义:

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

and I'm trying to wrap this in cython. 我正在尝试将其包装在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 eg double(*)(DataPoint&, DataPoint&) but this obviously results in a syntax error. 我怀疑问题出在定义的F部分,我尝试了各种方法来代替它,例如double(*)(DataPoint&, DataPoint&)但这显然会导致语法错误。

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. 据我所知,Cython不直接支持非类型模板参数(即函数指针是什么)(尽管我可能错过了备忘录),但是有一个众所周知的cname-hack可以实现这一目标。

Here, for a much simpler example: 在这里,为一个简单得多的示例:

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

ie an int -value as template parameter. 即一个int -value作为模板参数。

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期望T为类型,而g ++(或其他编译器)期望为整数值-这就是cname-hack出路

%%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. Cython认为val2是一种类型( int别名),但在结果的c ++代码( fun<2>() )中将其替换为2 ,因此c ++编译器会看到一个整数值(在这种情况下为2 )预计。


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. 如果您在Cython代码中的其他任何地方都没有使用“ euclidean_distance”,则实际上根本不需要包装它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM