Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Question

Is there a way to create a Python wrapper for Cython-wrapped C++ class with templates? (i.e. do exactly what is show here but with templates: http://docs.cython.org/src/userguide/wrapping_CPlusPlus.html#create-cython-wrapper-class).

I know about the fused types workaround (https://groups.google.com/forum/#!topic/cython-users/qQpMo3hGQqI) but that doesn't allow you to instatiate classes like vector<vector<int>>: the fused types have, quite unsurprisingly, no notion of recursion.

Rephrasing

What I would like to achieve is for a wrapped class like:

cdef extern from "header.h":
    cdef cppclass Foo[T]:
        Foo(T param)
        # ...

create a simple Python wrapper:

cdef class PyFoo[T]:  # I know the '[T]' can't be here, it's a wish
    cdef Foo[T] *thisptr
    def __cinit__(self, param):
        self.thisptr = new Foo[T](param)
    # ...

I'm quite certain that Cython doesn't support that per se, but maybe someone can think of a workaround. I'm not looking for idiomatic or nice examples, I'm just wondering if that's possible in any way.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
376 views
Welcome To Ask or Share your Answers For Others

1 Answer

As you say, Cython doesn't really support this.

I think by far the simplest approach is just to manually generate a bunch of Cython files using string substitution. Start with a "foowrapper.pxi.src" file (name as you wish...):

cdef class PyFoo_{T}:
  cdef Foo[{T}] *thisptr
  def __cinit__(self, param):
    self.thisptr = new Foo[{T}](param)
    # etc

Next, run it through a simple program (may as well be Python) to load the file, do the string substitution, and save the file again under a new name. The key line is just:

output = code.format(T=T) # where T is a string with a C++ class name 
              # e.g. "int" or "std::vector<double>"

(There's obviously a bit of code relating to loading and saving that I've skipped out of laziness)

Then, in your Cython file you just "include" the generated files for each class. The "include" command in Cython is a literal textual include (like the C preprocessor) and expects a .pxi file:

cdef extern from "header.h":
    cdef cppclass Foo[T]:
        Foo(T param)
        # ...

include "foowrapper_int.pxi"
include "foowrapper_vectordouble.pxi
# etc

You have to pick the classes to generate at compile time, but this is unavoidable (templates are a compile-time feature), so you're never going to be able to generate them dynamically from a Python scripting environment since the corresponding C++ class won't be generated.

Other options

A couple of other options are worth brief consideration. First, you could inherit Foo<T> from a base class (say FooBase) which doesn't depend on the template parameter. You'd then wrap FooBase in Cython (generating constructor-like functions for the cases you care about). This is only really viable if the functions you want to call don't have arguments that depend on the template type. Obviously this also involves changing the C++ code.

The section option is to look at a different way of wrapping. Boost Python will certainly support this natively (but comes with its own disadvantages). I imagine SIP/SWIG would also cope (but I don't know). You can could fairly cleanly mix-and-match these with Cython if necessary (by importing the generated module containing your template classes).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...