I'm trying to wrap an entire c++ template library with cython in order to let it available for python users. As I already mentioned, the library is template on both class and method of the class and as consequence, it is not compiled but "header-only".
Since the library is somewhat big, I decided to create a file as a starting point and trying to wrap it in cython and let it available as a python function.
The file, let call it easy.hpp
, reflects the way the library is written
#include <iterator>
#include <utility>
#include <vector>
#include <iostream>
namespace exNamespace {
class exClass
{
public:
template <typename T1, typename T2> void exMethod(T1 a, T2 b) const;
};
// Impl
template <typename T1, typename T2> void exClass::exMethod(T1 a, T2 b) const
{
for(auto i=0; i< a.size(); i++){
std::cout << a[i] << "-" << b[i] << "\n";
}
}
}
Following "Cython-A guide for Python programmers by Kurt Smith", I built two file:
tWrap.pxd
and tWrap.pyx
:
//tWrap.pxd
cdef extern from "easy.hpp" namespace "exNamespace":
cdef cppclass exClass:
void exMethod[T1,T2](T1 a, T2, b) except +
//tWrap.pyx
from libcpp.vector cimport vector
cimport tWrap
ctypedef vector[double].iterator vvit
cdef _process(v1, v2):
cdef vector[double] vv1
cdef vector[double] vv2
assert len(v1) == len(v2)
for elt1 in v1:
vv1.push_back(<double>elt1)
for elt2 in v2:
vv2.push_back(<double>elt2)
exClass.exMethod(vv1.begin(),vv2.begin())
def process(v1,v2):
_process(v1,v2)
The setup.py
is written as follow:
import os
from setuptools import setup, Extension
from setuptools.dist import Distribution
from Cython.Distutils import build_ext
Distribution(dict(setup_requires='Cython'))
ext_modules = [
Extension("test", ["tWrap.pyx"],
language="c++"
)
]
setup(
include_package_data=True,
package_data={'': ['*.pyx', '*.pxd', '*.h', '*.c']},
cmdclass = {'build_ext': build_ext},
ext_modules=ext_modules
)
In compiling stage, I get stuck with these errors:
Error compiling Cython file:
------------------------------------------------------------
...
assert len(v1) == len(v2)
for elt1 in v1:
vv1.push_back(<double>elt1)
for elt2 in v2:
vv2.push_back(<double>elt2)
exClass.exMethod(vv1.begin(),vv2.begin())
^
------------------------------------------------------------
tWrap.pyx:26:4: undeclared name not builtin: exClass
Error compiling Cython file:
------------------------------------------------------------
...
assert len(v1) == len(v2)
for elt1 in v1:
vv1.push_back(<double>elt1)
for elt2 in v2:
vv2.push_back(<double>elt2)
exClass.exMethod(vv1.begin(),vv2.begin())
^
------------------------------------------------------------
tWrap.pyx:26:30: Cannot convert 'iterator' to Python object
Error compiling Cython file:
------------------------------------------------------------
...
assert len(v1) == len(v2)
for elt1 in v1:
vv1.push_back(<double>elt1)
for elt2 in v2:
vv2.push_back(<double>elt2)
exClass.exMethod(vv1.begin(),vv2.begin())
^
------------------------------------------------------------
tWrap.pyx:26:42: Cannot convert 'iterator' to Python object
I have to admit to not fully understand how templates are managed in cython, since in the book the author always start from template function coming form std library.
I want to achieve something like:
import test
test.process([1,3,5],[2,4,6])
1-2
3-4
5-6
or by using list(containers) with printable (<< operator) types.
Update
Trying to get an instace of the class:
//tWrap.pyx
...
cdef class cClass:
cdef tWrap.exClass *_thisptr
def __cinit__(self):
self._thisptr = new tWrap.exClass()
def __dealloc__(self):
if self._thisptr != NULL:
del self._thisptr
...
cdef _process(self,v1, v2):
cdef vector[double] vv1
cdef vector[double] vv2
assert len(v1) == len(v2)
for elt1 in v1:
vv1.push_back(<double>elt1)
for elt2 in v2:
vv2.push_back(<double>elt2)
self._thisptr.exMethod(vv1.begin(),vv2.begin())
...
But fail in compilation with this error:
self._thisptr.exMethod(vv1.begin(),vv2.begin())
^
------------------------------------------------------------
tWrap.pyx:26:30: Call with wrong number of arguments (expected 3, got 2)