Search code examples
c++cythonwrapperstdtuple

workaround for wrapping C++ tuples in cython - a more explicit answer please


I need a cython wrapper for a tuple consisting of three elements all of the same type.

Now I know that this isn't directly supported by cython but that there is a workaround that is "explained" in the answer posted to a question found here: How to declare a c++ tuple in cython

this answer even provides a link to another "explanation" so I know I'm at risk of being accused of posting a "duplicate question." But...

the problem is I don't understand the answer because it is not explicit enough and possibly because it is more abstract than I need or want. There is one little code snippet provided as an example. I don't know where this code snippet should live, and no explanation of how to "export each tupleN".

I tried to ask for a more explicit answer in the comments but I'm not allowed to because my reputation isn't high enough yet. So my only recourse is to post this question.

So please suppose the following, I have a header called header.h in my C++ source where I define

typedef std::tuple<double*,double*,double*> Coordinate

elsewhere, I have a pxd file where I want to create my wrapper for this type. So I want to write something like the following:

cdef extern from "<tuple>" namespace "std":
    cdef cppclass cppTuple "tuple"[T,T,T]:
    tuple()

and then somewhere else I have a pyx file that defines a python class that has a pointer to a tuple.Say something like this:

cdef class PointType:
    cdef cppTuple[double*,double*,double*]* c_PointType_ptr

    def __cinit__(self):
        self.c_PointType_ptr = new cppTuple()

    def __dealloc__(self):
        del self.c_PointType_ptr

Now I know the details of this are wrong. But what - as explicitly as possible - is the right way? The answer provided in the link provided is not nearly explicit enough for me to be able to understand.

By the way: I'm not quite sure how to handle the typedef either, so if someone could be kind enough to clear up what to do about that too I'd really appreciate it.

Thank you.


Solution

  • The easiest thing is probably to drop the templates entirely and just implement the specific type of tuple you're using:

    cdef extern from "<tuple>":
        cdef cppclass Coordinate "std::tuple<double*, double*, double*>":
            Coordinate()
    

    Of course, since you already have the typedef you could just do:

    cdef extern from "header_where_you_defined_the_typedef":
        cdef cppclass Coordinate:
            Coordinate()
    

    Here Cython doesn't even need to know that it's a C++ std::tuple underneath.

    The cdef class is basically as you've written it:

    cdef class PointType:
        cdef Coordinate* c_PointType_ptr
    
        def __cinit__(self):
            self.c_PointType_ptr = new Coordinate()
    
        def __dealloc__(self):
            del self.c_PointType_ptr
    

    Really all Cython needs to know about Coordinate is that there's a class that exists called that.