如何在Cython中包装C++仿函数

Wil*_*ill 5 c++ python functor cython

我正在尝试包装一个C++库,其中逻辑被实现为.hpp文件中模板化的函子,我正在努力找到将C++函子暴露为Cython/Python函数的正确方法.下面的算符如何被Cython包裹?

根据Cython 0.20文档,我认为这应该是可能的,至少对于模板类和函数而言.

注意:我想我已经弄清楚了如何包装普通的C++函数 - 当我试图包装一个模板化仿函数时出现问题,一个struct重载()运算符的模板(当数据类型被修复时它就像一个函数一样) ).

免责声明:我是C++的新手,也是Cython的新手,如果我在这里犯了明显的错误,请道歉.


我试图包装的仿函数:

#include <vector>
#include "EMD_DEFS.hpp"
#include "flow_utils.hpp"

template<typename NUM_T, FLOW_TYPE_T FLOW_TYPE= NO_FLOW>
struct emd_hat_gd_metric {
    NUM_T operator()(const std::vector<NUM_T>& P, const std::vector<NUM_T>& Q,
                     const std::vector< std::vector<NUM_T> >& C,
                     NUM_T extra_mass_penalty= -1,
                     std::vector< std::vector<NUM_T> >* F= NULL);
};
Run Code Online (Sandbox Code Playgroud)

我的wrapper.pyx档案:

# distutils: language = c++

from libcpp.vector cimport vector


cdef extern from "lib/emd_hat.hpp":
    # Apparently `cppclass` is necessary here even though 
    # `emd_hat_gd_metric` is not a class...?
    cdef cppclass emd_hat_gd_metric[NUM_T]:
        NUM_T operator()(vector[NUM_T]& P,
                         vector[NUM_T]& Q,
                         vector[vector[NUM_T]]& C) except +

cdef class EMD:

    cdef emd_hat_gd_metric *__thisptr

    def __cinit__(self):
        self.__thisptr = new emd_hat_gd_metric()

    def __dealloc__(self):
        del self.__thisptr

    def calculate(self, P, Q, C):
        # What goes here? How do I call the functor as a function?
        return self.__thisptr(P, Q, C)
Run Code Online (Sandbox Code Playgroud)

上面只是Calling non-function type 'emd_hat_gd_metric[NUM_T]'在我尝试编译时出错cython --cplus wrapper.pyx.

这是我想要包装的完整库.

最终目标:能够emd_hat_gd_metric作为Cython/Python函数调用,参数为NumPy数组.

Wil*_*ill 3

我找不到真正的解决方案,但这里有一个解决方法(需要修改 C++ 代码):只需在 C++ 标头中使用所需的数据类型实例化模板函数,然后在文件中正常声明该函数即可.pyx

\n\n

如果您需要许多不同的数据类型,这有点笨拙,但我只需要double. 如果不需要修改外部库\xe2\x80\xa6但它可以工作,那就更好了。

\n\n
\n\n

在 C++some_library.hpp文件中:

\n\n

使用您需要的数据类型实例化函子(例如double):

\n\n
template<typename T>\nstruct some_template_functor {\n    T operator()(T x);\n};\n\n// Add this:\nsome_template_functor<double> some_template_functor_double;\n
Run Code Online (Sandbox Code Playgroud)\n\n

在 Cython.pyx文件中:

\n\n

正常声明函数(不需要cppclass):

\n\n
cdef extern from "path/to/some_library.hpp":\n    cdef double some_template_functor_double(double x)\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后您可以some_template_functor_double从 Cython 内部调用。

\n