Simple template class wrapping

469 views
Skip to first unread message

Jonathan Hanke

unread,
Nov 27, 2014, 10:45:43 PM11/27/14
to cython...@googlegroups.com
Hi,

I'm trying to wrap a simple templated C++ class example in Cython that uses the template to determine the datatype of an underlying vector.  I used the vector templating code from the example in the Cython documentation (which seems important to include in the .pyx file), and tried to do something similar.

Here the C++ class is "Thing" and the Cython class wrapping it is "PyThingINT".  The error appears when I try to import the class into python with "from mything import PyThingINT", giving 

ImportError: dlopen(/Users/jonhanke/Desktop/Cython_template_example__2014-11-27/mything.so, 2): Symbol not found: __ZN7MySpace5ThingIiEC1El
  Referenced from: /Users/jonhanke/Desktop/Cython_template_example__2014-11-27/mything.so
  Expected in: flat namespace
 in /Users/jonhanke/Desktop/Cython_template_example__2014-11-27/mything.so

I've included the files below.  Any comments are appreciated.  Thanks!

-Jon

=====================================================
File thing.h:
----------------
#if !defined(THING_H)
#define THING_H

namespace MySpace {

#include <vector>
using namespace std;

template <class T> class Thing {

public:
  Thing(const long precision);
  ~Thing();

  long num() const;


private:
  vector<T> _vec;
  long _num;
};


}  // end of namespace                                                                             


#endif

---------------------------------------------------------------------------
File thing.cpp:
------------------- 
#include <vector>
#include "thing.h"


namespace MySpace {

using namespace std;


template <class T> Thing<T>::Thing(const long num){
  vector<T> new_vec(num+1, 0);  // Fill the new_series vector with zeros                           
  _vec = new_vec;
  _num = num;
}


// Empty Destructor                                                                                
template <class T> Thing<T>::~Thing(){ }


template <class T> long Thing<T>::num() const {
  return _num;
}


};  // End of namespace    

------------------------------------------------------------------------------
File mything.pyx:
----------------------

# distutils: language = c++
# distutils: sources = ['thing.cpp']
# distutils: include_dirs = ['/usr/local/include']
# distutils: libraries = []
# distutils: library_dirs = ['/usr/local/lib']

from libcpp cimport long

cdef extern from "<vector>" namespace "std":
    cdef cppclass vector[T]:
        cppclass iterator:
            T operator*()
            iterator operator++()
            bint operator==(iterator)
            bint operator!=(iterator)
        vector()
        void push_back(T&)
        T& operator[](int)
        T& at(int)
        iterator begin()
        iterator end()


cdef extern from "thing.h" namespace "MySpace":
     cdef cppclass Thing[T]:
            Thing(const long num) except +

cdef class PyThingINT:
    cdef Thing[int] *thisptr
    def __cinit__(self, prec):
        self.thisptr = new Thing[int](<long> prec)
    def __dealloc__(self):
        del self.thisptr

Björn Dahlgren

unread,
Dec 1, 2014, 1:50:03 PM12/1/14
to cython...@googlegroups.com

I've included the files below.  Any comments are appreciated.  Thanks!

-Jon


Hi Jon,

You have 2 choices:

1. Put your implementation in the header and drop the .cpp file ("head only library")
2. Add this to the end of your .cpp file: template class MySpace::Thing<int>;

The latter will make your compiler compile one version for <int> in thing.o and the symbol will be defined,
the former will let the compiler compile a version for <int> when compiling the cython generated mything.cpp file since the whole implementation is "#include":ed.

Best regards,
/Björn Dahlgren

Jonathan Hanke

unread,
Dec 11, 2014, 10:24:18 PM12/11/14
to cython...@googlegroups.com
Hi Bjorn,

Thanks a lot.  That's very helpful.  I went with the second option (separate .cc and .h files), which works well enough if I'm careful to know exactly what types are being used.  Thanks,

-Jon

Robert Bradshaw

unread,
Dec 11, 2014, 11:37:27 PM12/11/14
to cython...@googlegroups.com
On Thu, Nov 27, 2014 at 7:45 PM, Jonathan Hanke <jonh...@gmail.com> wrote:
> Hi,
>
> I'm trying to wrap a simple templated C++ class example in Cython that uses
> the template to determine the datatype of an underlying vector. I used the
> vector templating code from the example in the Cython documentation (which
> seems important to include in the .pyx file), and tried to do something
> similar.
>
> Here the C++ class is "Thing" and the Cython class wrapping it is
> "PyThingINT". The error appears when I try to import the class into python
> with "from mything import PyThingINT", giving
>
> ImportError:
> dlopen(/Users/jonhanke/Desktop/Cython_template_example__2014-11-27/mything.so,
> 2): Symbol not found: __ZN7MySpace5ThingIiEC1El
> Referenced from:
> /Users/jonhanke/Desktop/Cython_template_example__2014-11-27/mything.so
> Expected in: flat namespace
> in /Users/jonhanke/Desktop/Cython_template_example__2014-11-27/mything.so
>
>
> I've included the files below. Any comments are appreciated. Thanks!

> # distutils: language = c++
> # distutils: sources = ['thing.cpp']
> # distutils: include_dirs = ['/usr/local/include']
> # distutils: libraries = []
> # distutils: library_dirs = ['/usr/local/lib']
>
> from libcpp cimport long

Note that you don't need to cimport long.

> cdef extern from "<vector>" namespace "std":
> cdef cppclass vector[T]:
> cppclass iterator:
> T operator*()
> iterator operator++()
> bint operator==(iterator)
> bint operator!=(iterator)
> vector()
> void push_back(T&)
> T& operator[](int)
> T& at(int)
> iterator begin()
> iterator end()

On the other hand, you don't have to declare this youreself. Just do

from libcpp.vector cimport vector

> cdef extern from "thing.h" namespace "MySpace":
> cdef cppclass Thing[T]:
> Thing(const long num) except +
>
> cdef class PyThingINT:
> cdef Thing[int] *thisptr
> def __cinit__(self, prec):
> self.thisptr = new Thing[int](<long> prec)
> def __dealloc__(self):
> del self.thisptr

The cast to <long> is unneeded, it will be done implicitly due to the
type of the argument.

- Robert

Jonathan Hanke

unread,
Dec 19, 2014, 7:01:45 PM12/19/14
to cython...@googlegroups.com
Hi,

I had a followup question about explicit instantiation of function templates when using separate .h and .cpp files.  I have a function in the .cpp file 

template <class T>
valarray
<T> VectorTrim(valarray<T> & v) { ... }

which I've tried to explicitly instantiate for Cython by adding either of the two lines

template valarray<int> VectorTrim(valarray<int>);
template valarray<int> VectorTrim<int>(valarray<int>);

However this gives an error 

valarray_extras.cpp:161:26: error: explicit instantiation of 'VectorTrim' does not refer to a function template, variable template, member function, member class, or
      static data member
  template valarray<int> VectorTrim(valarray<int>);
                         ^
valarray_extras.cpp:68:13: note: candidate template ignored: could not match 'valarray<type-parameter-0-0> &' against 'std::valarray<int>'
valarray<T> VectorTrim(valarray<T> & v) {

What is the correct syntax for doing this?  

Thanks,

-Jon

P.S.  Also, thanks a lot for the code simplification comments!

Björn Dahlgren

unread,
Dec 20, 2014, 4:08:31 PM12/20/14
to cython...@googlegroups.com

On Saturday, 20 December 2014 01:01:45 UTC+1, Jonathan Hanke wrote:


It's supposed to be a reference right (note the &)?

template valarray<int> VectorTrim<int>(valarray<int> &);

I think that should do it..

Best
/Björn

Jonathan Hanke

unread,
Dec 20, 2014, 10:27:43 PM12/20/14
to cython...@googlegroups.com
Yes, thanks a lot.  That works.  Best,

-Jon
Reply all
Reply to author
Forward
0 new messages