I have a template class, which I want to expose through a Cython interface so that the user will be able to choose, which data type gets used.
I have the following files:
my_class.h
andmy_class.cpp
my_class.pxd
andmy_class.pyx
setup.py
my_class.h
#include <iostream>
namespace my_namespace
{
template<class T> class MyClass
{
public:
MyClass();
~MyClass();
void foo();
};
}
my_class.cpp
#include "my_class.h"
namespace my_namespace
{
template<class T>MyClass<T>::MyClass()
{
std::cout << "Constructor of MyClass" << std::endl;
}
template<class T>MyClass<T>::~MyClass()
{
std::cout << "Destructor of MyClass" << std::endl;
}
template<> void MyClass<float>::foo()
{
std::cout << "foo() using float" << std::endl;
}
template<> void MyClass<double>::foo()
{
std::cout << "foo() using double" << std::endl;
}
}
my_class.pxd
# cython: language_level = 3
cdef extern from "my_class.cpp":
pass
cdef extern from "my_class.h" namespace "my_namespace":
cdef cppclass MyClass[T]:
MyClass() except +
void foo()
my_class.pyx
# cython: language_level = 3
# distutils: language = c++
from my_class import MyClass
cdef class PyMyClass:
cdef MyClass[T] cls_ptr
def __init__(self, prec="float"):
if prec == "float":
self.cls_ptr = MyClass[float]()
elif prec == "double":
self.cls_ptr = MyClass[double]()
else:
raise TypeError(f"MyClass is not implemented for `{prec}`")
def foo(self):
return self.cls_ptr.foo()
setup.py
from Cython.Build import cythonize
from setuptools import Extension, setup
setup(
name="myClass",
ext_modules=cythonize(
Extension(
"myClass",
sources=["my_class.pyx"],
extra_compile_args=["-g", "-march=native"],
language="c++",
),
language_level=3,
),
)
When I compile the module using python setup.py build_ext --inplace --force
I get various compilation errors, like 'MyClass' is not a type identifier
and even undeclared name not builtin: double
.
I have tried moving around the [T]
expression to multiple places, but no luck.
My goal is, that the user can write something like this:
>>> import myClass
>>> a = myClass.PyMyClass()
Constructor of MyClass
>>> a.foo()
foo() using float
>>> b = myClass.PyMyClass(prec="double")
Constructor of MyClass
>>> b.foo()
foo() using double