I have a class Foo
with a member x
that I want to expose, but via a getter function rather than a property. I just discovered make_getter
, so I thought I'd give that a go:
#include <boost/python.hpp>
namespace py = boost::python;
struct Base {
int x;
};
struct Foo : Base {
Foo(int i): Base{i} { }
};
BOOST_PYTHON_MODULE(Foo)
{
py::class_<Foo>("Foo", py::init<int>())
.def_readonly("x", &Foo::x)
.def("getX", py::make_getter(&Foo::x))
;
}
This, however, fails:
>>> import Foo
>>> f = Foo.Foo(42)
>>> f.x
42
>>> f.getX()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
Foo.getX(Foo)
did not match C++ signature:
getX(Base {lvalue})
>>>
What does that error even mean? Clearly the signatures match! How can I fix this?
The issue, if you carefully examine the
ArgumentError
exception is that, you are callinggetX()
with aFoo
:whereas the data member you are trying to access is really a member of
Base
:Boost.Python needs to perform a conversion from a lvalue
Foo
to an lvalueBase
, and you haven't actually told Boost that it can do that. The problem ultimately stems from the fact that&Base::x
is anint Base::*
instead of anint Foo::*
, so the template deduction inboost::python::make_getter
makes a function that takes aBase
instead of aFoo
.The simplest solution is to ensure that you pass in the correct pointer-to-member to
make_getter
:With that cast, everything works:
That's a little tedious though, so you could instead write a quick method/macro to do it for you:
With which you can do:
Alternatively, you could tell Boost.Python about the hierarchy directly:
This way,
Foo
inheritsgetX()
and all is well.