I have an structure in c as follows
typedef struct _person{
int id[10];
int number[10];
}person;
How can one bind this using pybind11?
There does not seem to be a pretty way AFAICT when you want the data to be writable (it's somewhat less contrived when the data would be readonly). Anyway, the following does the trick, assuming you have numpy installed:
#include <pybind11/pybind11.h>
#include <pybind11/pytypes.h>
#include <pybind11/numpy.h>
typedef struct _person{
int id[10];
int number[10];
} person;
PYBIND11_MODULE(person, m)
{
pybind11::class_<person>(m, "person", pybind11::buffer_protocol())
.def(pybind11::init<>())
.def_property("id", [](person &p) -> pybind11::array {
auto dtype = pybind11::dtype(pybind11::format_descriptor<int>::format());
auto base = pybind11::array(dtype, {10}, {sizeof(int)});
return pybind11::array(
dtype, {10}, {sizeof(int)}, p.id, base);
}, [](person& p) {})
.def_property("number", [](person &p) -> pybind11::array {
auto dtype = pybind11::dtype(pybind11::format_descriptor<int>::format());
auto base = pybind11::array(dtype, {10}, {sizeof(int)});
return pybind11::array(dtype, {10}, {sizeof(int)}, p.number, base);
}, [](person& p) {});
}
The ticket is to provide the empty base object which makes the array behave as a view object. Without the base, it makes a copy. You do not need the property setter (that would, if implemented, set the array, not the array items) and could raise an error instead of providing the no-op as I did. Also, if you really have two same-sized arrays, you can use a helper function instead of the lambdas.
The basic problem for binding C builtin arrays is that python does not have a proper array type (there is a basic memory view and the module array, but no true array type), hence you need to get one from somewhere and pybind11 prefers to take the one from numpy as it's the best game in town.
Just to show you an alternative, in cppyy (http://cppyy.org), I took a different tack: it has a low-level array view, which can subsequently be handed to numpy for view or copying as desired, since it implements the full buffer protocol. The advantage here is that it's the python user who can decide on the final use. The disadvantage is that if you're going to use numpy anyway, it's an extra step. But it's also directly usable without numpy installed:
import cppyy
cppyy.cppdef("""
typedef struct _person{
int id[10];
int number[10];
} person;
""")
p = cppyy.gbl.person()
print(len(p.id), p.id)
print(list(p.id))
which produces:
(10, <cppyy.LowLevelView object at 0x105ab33b0>)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]