【问题标题】:Wrapping C++ code with function pointer as template parameter in cython用函数指针包装 C++ 代码作为 cython 中的模板参数
【发布时间】:2018-12-02 17:45:26
【问题描述】:

我正在尝试在 cython 中包装以下用 C++ 编写的声明:

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

我在 C++ 中也有以下定义:

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

我正在尝试将其包装在 cython 中。这是我能够按照文档提出的内容:

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

并围绕它构建一个包装器:

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

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

很遗憾,这会导致以下错误:

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

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

我怀疑问题出在定义的F 部分,我已经尝试了各种方法来代替它,例如double(*)(DataPoint&amp;, DataPoint&amp;) 但这显然会导致语法错误。

【问题讨论】:

    标签: python c++ cython


    【解决方案1】:

    据我所知,Cython 不直接支持非类型模板参数(即函数指针)(虽然我可能错过了备忘录),但有一个众所周知的 cname-hack 实现目标。

    这里有一个更简单的例子:

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

    int-value 作为模板参数。

    现在我们进退两难了:Cython 期望 T 是类型,而 g++(或其他编译器)期望整数值 - cname-hack 来拯救我们:

    %%cython --cplus            
    ...
    cdef extern from *:
        ctypedef int val2 "2" 
    
    def doit():
        return fun[val2]()
    

    Cython 认为 val2 是一种类型(int 的别名),但在生成的 c++ 代码 (fun&lt;2&gt;()) 中将其替换为 2,因此 c++ 编译器会看到一个整数值 (@987654328 @ 在这种情况下),正如它所期望的那样。


    对于您的情况,这意味着添加:

    %%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]()
    

    如果您不在 Cython 代码的其他任何地方使用它,您实际上根本不需要包装“euclidean_distance”。

    【讨论】:

    • 哇,这是一个巧妙的技巧。我以前没有遇到过。非常感谢!
    猜你喜欢
    • 2020-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多