21

I'd like to use PyBind11 to wrap a specialized array class. However, the array is available in many flavours (one per each plain-old-datatype). The code looks like this:

py::class_<Array2D<float>>(m, "Array2Dfloat", py::buffer_protocol(), py::dynamic_attr())
    .def(py::init<>())
    .def(py::init<Array2D<float>::xy_t,Array2D<float>::xy_t,float>())
    .def("size",      &Array2D<float>::size)
    .def("width",     &Array2D<float>::width)
    .def("height",    &Array2D<float>::height)
    //...
    //...

The only way I've thought of to tell PyBind11 about these classes is by duplicating the above for each POD through the use of a very large macro.

Is there a better way to do this?

Richard
  • 56,349
  • 34
  • 180
  • 251

1 Answers1

38

You can avoid using macros and instead go with a templated declaration function:

template<typename T>
void declare_array(py::module &m, std::string &typestr) {
    using Class = Array2D<T>;
    std::string pyclass_name = std::string("Array2D") + typestr;
    py::class_<Class>(m, pyclass_name.c_str(), py::buffer_protocol(), py::dynamic_attr())
    .def(py::init<>())
    .def(py::init<Class::xy_t, Class::xy_t, T>())
    .def("size",      &Class::size)
    .def("width",     &Class::width)
    .def("height",    &Class::height);
}

And then call it multiple times:

declare_array<float>(m, "float");
declare_array<int>(m, "int");
...
Hannes Ovrén
  • 21,229
  • 9
  • 65
  • 75
  • 12
    In case anyone else was confused, those `declare_array` calls still need to go inside a `PYBIND11_MODULE(my_module_name, m)` call. – Tom Ellis Jul 24 '19 at 16:12
  • How can I extend this to allow for templated methods in the class? In my example it fails to compile if, for example, the method 'size' is templated (say I want to expose the function size). However, If for instance I where to replace 'Class' by 'Array2D' in the definition of size it would compile. The problem is that then I could not use your solution to avoid repeating code... – Guillermo BCN Nov 22 '20 at 09:36
  • can anyone please take a look in [here](https://stackoverflow.com/questions/66227840/how-to-wrap-class-template-consisting-virtual-function-with-pybind?noredirect=1#comment117115200_66227840). I have taken help from this **answer** too. – user10634362 Feb 18 '21 at 10:42