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

时间:2014-02-27 00:45:16

标签: python c++ cython functor

我正在尝试包装一个C ++库,其中逻辑被实现为.hpp文件中的模板化仿函数,我正在努力找到将C ++仿函数公开为Cython / Python函数的正确方法。像下面那样的仿函数应该如何用Cython包装?

我认为这应该是可行的,至少对于模板类和函数来说,根据Cython 0.20 docs

注意:我想我已经弄清楚如何包装普通的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);
};

我的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)

当我尝试使用Calling non-function type 'emd_hat_gd_metric[NUM_T]'进行编译时,上面只会出现cython --cplus wrapper.pyx错误。

Here's the full library I'm trying to wrap.

结束目标:能够将emd_hat_gd_metric作为Cython / Python函数调用,参数为NumPy数组。

1 个答案:

答案 0 :(得分:2)

我找不到真正的解决方案,但这是一种解决方法(需要修改C ++代码):只需在C ++标头中使用所需的数据类型实例化模板函数,然后在{{{ 1}}文件。

如果您需要许多不同的数据类型,这有点笨拙,但我只需要.pyx。如果没有必要修改外部库,它也会更好......但是它可以工作。


在C ++ double文件中:

使用您需要的数据类型(例如,some_library.hpp)实例化仿函数:

double

在Cython template<typename T> struct some_template_functor { T operator()(T x); }; // Add this: some_template_functor<double> some_template_functor_double; 文件中:

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

cppclass

然后你可以在Cython中调用cdef extern from "path/to/some_library.hpp": cdef double some_template_functor_double(double x)