Boost python getter/setter with the same name
Asked Answered
C

1

9

I am wrapping C++ classes with boost-python and I am wondering is there is a better way to do it than what I am doing now.

The problem is that the classes have getters/setters that have the same name and there doesn't seem to be a painless way to wrap this with boost-python.

Here is a simplified version of the problem. Given this class:

#include <boost/python.hpp>

using namespace boost::python;

class Foo {
public:
    double
    x() const
    {
        return _x;
    }

    void
    x(const double new_x)
    {
        _x = new_x;
    }

private:
    double _x;
};

I would like to do something like:

BOOST_PYTHON_MODULE(foo)
{
    class_<Foo>("Foo", init<>())
        .add_property("x", &Foo::x, &Foo::x)
    ;
}

This doesn't work because boost-python can't figure out which version of the function to use.

In fact, you can't even do

.def("x", &Foo::x)

for the same reason.

I was re-reading the tutorial at boost.org and the section on overloading seemed super promising. Unfortunately it doesn't seem to be what I'm looking for.

In the overloading section, it mentions a BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS macro that works like this:

if there were another member function in Foo that took defaulted arguments:

void z(int i=42)
{
    std::cout << i << "\n";
}

you can then use the macro:

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(z_member_overloads, z, 0, 1)

and then in the BOOST_PYTHON_MODULE:

.def("z", &Foo::z, z_member_overloads())

z_member_overloads lets you call def once and it will expose methods to python for both 0 arguments and 1 argument.

I was hoping that this would work for my x() and x(double val) getter/setter, but it doesn't work.

doing:

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(x_member_overloads, x, 0, 1)
...
.def("x", &Foo::x, x_member_overloads())

doesn't compile:

error: no matching member function for call to 'def'

.def("x", &Foo::x, x_member_overloads())
~^~~

Question: So, is there another macro or something that can make this work?

For completeness, this is how I'm currently handling cases like this:

    .add_property(
        "x",
        make_function(
            [](Foo& foo) {
                return foo.x();
            },
            default_call_policies(),
            boost::mpl::vector<double, Foo&>()
        ),
        make_function(
            [](Foo& foo, const double val) {
                foo.x(val);
        },
        default_call_policies(),
        boost::mpl::vector<void, Foo&, double>()
        )
    )
Contractual answered 28/5, 2017 at 20:22 Comment(0)
S
3

You can do this by casting to appropriate overload (untested):

class_<Foo>("Foo", init<>())
        .add_property("x", 
                      static_cast< double(Foo::*)() const >(&Foo::x), // getter
                      static_cast< void(Foo::*)(const double) >(&Foo::x)) // setter
    ;
Sketch answered 29/5, 2017 at 9:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.