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
ArgumentErrorexception 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
Footo an lvalueBase, and you haven't actually told Boost that it can do that. The problem ultimately stems from the fact that&Base::xis anint Base::*instead of anint Foo::*, so the template deduction inboost::python::make_gettermakes a function that takes aBaseinstead 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,
FooinheritsgetX()and all is well.