Повысьте геттер/сеттер python с тем же именем

Я оборачиваю классы С++ с помощью boost-python, и мне интересно, есть ли лучший способ сделать это, чем то, что я делаю сейчас.

Проблема в том, что у классов есть геттеры/сеттеры с одинаковыми именами, и кажется, что нет безболезненного способа обернуть это с помощью boost-python.

Вот упрощенная версия проблемы. Учитывая этот класс:

#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;
};

Я хотел бы сделать что-то вроде:

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

Это не работает, потому что boost-python не может определить, какую версию функции использовать.

На самом деле, вы даже не можете сделать

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

по той же причине.

Я перечитывал учебник на boost.org и раздел о перегрузке казался многообещающим. К сожалению, похоже, это не то, что я ищу.

В разделе перегрузки упоминается макрос BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS, который работает следующим образом:

если бы в Foo была другая функция-член, которая принимала аргументы по умолчанию:

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

затем вы можете использовать макрос:

BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(z_member_overloads, z, 0, 1)

а затем в BOOST_PYTHON_MODULE:

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

z_member_overloads позволяет вам вызвать def один раз, и он предоставит методы python как для 0 аргументов, так и для 1 аргумента.

Я надеялся, что это сработает для моих геттеров/сеттеров x() и x(double val), но это не сработало.

делает:

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

не компилируется:

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

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

Вопрос: Итак, есть ли другой макрос или что-то, что может заставить это работать?

Для полноты, вот как я сейчас обрабатываю такие случаи:

    .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>()
        )
    )

person Stephen    schedule 28.05.2017    source источник


Ответы (1)


Вы можете сделать это, приведя к соответствующей перегрузке (непроверенной):

class_<Foo>("Foo", init<>())
        .add_property("x", 
                      static_cast< double(Foo::*)() const >(&Foo::x), // getter
                      static_cast< void(Foo::*)(const double) >(&Foo::x)) // setter
    ;
person doqtor    schedule 29.05.2017