0

I have a C++ class Box that I want to wrap up using python C++ api.

The class is defined as:

class Box {
   public:
      int id;   

      Box(double l, double b, double h);

      double getVolume(void); 

      void setLength( double len );

   private:
      double length;      // Length of a box
      double breadth;     // Breadth of a box
      double height;      // Height of a box
};

In the C-API I have the following declaration of PyBox:

typedef struct 
{
    PyObject_HEAD
    Box *bx;
} PyBox;

and the following members table:

static PyMemberDef pyBox_members[] = {
    {"id", T_INT, offsetof(PyBox, bx->id), 0, "Box id"},
    {NULL}  /* Sentinel */
};

However, when I try to compile the module I get the following error message:

error: cannot apply ‘offsetof’ to a non constant address
     {"id", T_INT, offsetof(PyBox, bx->id), 0, "Box id"},
                   ^~~~~~~~

How do I specify the correct offsetof so that the member id corresponds to the public attribute bx->id?

Thanks!

R.J. Dunnill
  • 2,049
  • 3
  • 10
  • 21
PintoDoido
  • 1,011
  • 16
  • 35

1 Answers1

1

The basic issue is that bx is a pointer, so bx->id could literally anywhere in memory relative to PyBox. Therefore offsetof can never work and thus defining the members in PyMemberDef also can never work.

One solution would be to change the class definition so Box is part of the class (and so an offset is meaningful). This may or may not make sense depending on your C++ code:

typedef struct 
{
    PyObject_HEAD
    Box *bx;
} PyBox;

The better solution would be to use PyGetSetDef instead to define property getters and setters for bx->id.

DavidW
  • 29,336
  • 6
  • 55
  • 86
  • Thanks! But how do I use the PyGetSetDef without defining PyMemberDef? The official docs do not contain that case AFAIK https://docs.python.org/3.5/extending/newtypes.html. – PintoDoido May 10 '19 at 09:31
  • 1
    If you don't need it you just set `tp_members` to 0. – DavidW May 10 '19 at 09:41
  • Thinking about it... if the attribute is public why do we need a getter/setter? – PintoDoido May 10 '19 at 15:46
  • 1
    Because the getter/setter is the C++ <-> Python translation layer. Even when you use `PyMemberDef` then Python automatically generates a getter and setter to convert between `PyObject` and the C++ type. In this case the role of the getter/setter is also to figure out where `bx` is using the pointer. – DavidW May 10 '19 at 15:50