如何在Cython中定义C++模板函数类型?

4

A.hpp

// A.hpp
#ifndef RECTANGLE_HPP
#define RECTANGLE_HPP
#include <iostream>
#include <vector>
namespace test {

double euclid_dist(const std::vector<double> & a) {
  return 3.1415926;
}

template <class T, 
          double (*dist)(const std::vector<T> &)>
class foo {
 public:
  foo(std::vector<T> _items) {
   items = _items;
  }  
  ~foo() {} 
  void inside() {
    std::cout << "hello" << std::endl;
  }  
  void func() {
    inside();
  }  
  void prt(std::vector<std::vector<T> > a) {
    if(a.size() >= 1) {
      std::cout << euclid_dist(a[0]) << std::endl;
    }  
  }  
 private:
  std::vector<T> items;
}; // class foo
} // namespace test 
#endif

demo.pyx:

# demo.pyx
# distutils: language = c++
from libcpp.vector cimport vector
cdef extern from "A.hpp" namespace "test":
  double euculid_dist(const vector [double] & a) 

#def test_euclid_dist(const vector [double] a):
#    return euclid_dist(a)

cdef extern from "A.hpp" namespace "test":
  cdef cppclass foo [double, euclid_dist]:
      foo (vector[double]) except +
      void func()
      void prt(vector[vector[double]])

cdef class PyFoo:
    cdef foo *thisptr      # hold a C++ instance which we're wrapping
    def __cinit__(self, vec):
        self.thisptr = new foo(vec)
    def __dealloc__(self):
        del self.thisptr
   def func(self):
        self.thisptr.func()
   def prt(self, d):
        self.thisptr.prt(d)

setup.py

from distutils.core import setup, Extension
from Cython.Build import cythonize

setup(ext_modules = cythonize(Extension(
    "demo",                                # the extesion name
    sources=["demo.pyx"], # the Cython source and additional C++ source files
    language="c++", # generate and compile C++ code
)))

当我使用python setup.py build_ext --inplace编译时,出现以下错误:

Compiling demo.pyx because it changed.
Cythonizing demo.pyx
running build_ext
building 'demo' extension
x86_64-pc-linux-gnu-g++ -pthread -fPIC -I/usr/include/python2.7 -c         
demo.cpp -o build/temp.linux-x86_64-2.7/rect.o
demo.cpp:551:20: error: ‘euclid_dist’ was not declared in this scope
demo.cpp:551:31: error: template argument 2 is invalid
demo.cpp: In function ‘int __pyx_pf_4rect_5PyFoo___cinit__(__pyx_obj_4rect_PyFoo*, PyObject*)’:
demo.cpp:866:20: error: ‘euclid_dist’ was not declared in this scope
demo.cpp:866:31: error: template argument 2 is invalid
demo.cpp:866:43: error: invalid type in declaration before ‘;’ token
demo.cpp:881:38: error: ‘euclid_dist’ cannot appear in a constant-expression
demo.cpp:881:49: error: template argument 2 is invalid
demo.cpp:881:60: error: cannot convert ‘std::vector<double>’ to ‘intin initialization
demo.cpp: In function ‘PyObject* __pyx_pf_4rect_5PyFoo_4func(__pyx_obj_4rect_PyFoo*)’:
demo.cpp:984:26: error: request for member ‘func’ in ‘* __pyx_v_self->__pyx_obj_4rect_PyFoo::thisptr’, which is of non-class typeint’
demo.cpp: In function ‘PyObject* __pyx_pf_4rect_5PyFoo_6prt(__pyx_obj_4rect_PyFoo*, PyObject*)’:
demo.cpp:1038:26: error: request for member ‘prt’ in ‘* __pyx_v_self->__pyx_obj_4rect_PyFoo::thisptr’, which is of non-class typeint’
error: command 'x86_64-pc-linux-gnu-g++' failed with exit status 1

看起来在作用域中找不到 euclid_dist 函数,但我认为它在全局作用域中。上面的代码有什么问题吗?谢谢!


你这里真的是想用 eculid 而不是 euclid 吗?如果是,你拼写一直都是这样吗? - abarnert
另外,我从未尝试过将原始函数指针作为Cython的编译时模板参数传递...也许你必须明确要求函数指针?如果是这样,我不确定该怎么做。但是作为一个测试,您可以尝试在C++代码中创建一个全局double (*eculid_dist_p)(const std::vector<T> &) = &eculid_dist,然后从Cython引用它而不是从eculid_dist,看看是否有效。 - abarnert
@abarnert,在这种情况下,我该如何修改我的 pyx 文件以从 cpp 文件中导入变量? - xunzhang
我不知道。但是你有没有做我建议的测试来确认它是否工作了呢?如果是这样的话,那么你有一个非常具体的问题,Cython专家可能可以回答你(如果他们不能,那么还有一个最后的应急方案);如果没有,那么至少我们会有更多信息。 - abarnert
1个回答

4

Cython目前还不支持非类型模板参数,但是有一种有点hack的解决方法。

当您创建类的Cython定义时,您提供了显式的模板实例化,这样Cython就不需要知道类的模板性质。

在您的情况下,foo的定义将是:

cdef extern from "A.hpp" namespace "test":
    cdef cppclass foo "test::foo<double, test::euclid_dist>":
        foo(const vector[double] &) except +
        #... other members

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接