Как добавить пользовательское неявное преобразование в тип C ++ в Boost :: Python? - PullRequest
2 голосов
/ 10 августа 2009

В моем C ++-коде у меня есть класс Foo со многими методами, принимающими переменную типа Bar в качестве аргумента:

class Foo {
public:
  void do_this(Bar b);
  void do_that(Bar b);
  /* ... */
};

Bar имеет несколько конструкторов, которые создают новый объект из многих распространенных типов, таких как int, std :: string, float и т.д .:

class Bar {
public:
  Bar(int i);
  Bar(float f);
  Bar(std::string s);
  /* ... */
};

Я обернул это с помощью Boost :: Python и теперь я могу вызывать мои методы Foo напрямую, используя литералы Python, поскольку они неявно преобразуются в объекты Bar.

f = Foo()
f.do_this(5)
f.do_that("hello")

Теперь я хотел бы иметь возможность использовать и другие типы Python, такие как кортежи, например:

f.do_that((1,2,3))

Но я не хочу касаться исходного определения Bar, и я не хочу загрязнять мою библиотеку C ++ с помощью Boost :: Python. Я хочу написать функцию-обертку в своем коде привязки, но я просто не могу понять, возможно ли это и как это правильно сделать.

Другими словами: можно ли зарегистрировать фабричную функцию для автоматического преобразования в Python?

Ответы [ 6 ]

2 голосов
/ 09 ноября 2010

Панель подклассов рядом с кодом оболочки и дает вашему подклассу ctor, который принимает bp :: object (или более специфический тип python)

struct Bar_wrapper:Bar,bp::wrapper<Bar>
{
    Bar_wrapper(bp::object arg)
    {
        //code to build a Bar_wrapper Here
    }
}

Затем экспортируйте Bar_wrapper в python вместо Bar и назовите его Bar в качестве имени python:

class<Bar_wrapper>("Bar")
    ...
    .def(init<bp::object>())
    ...
1 голос
/ 13 сентября 2011

Добавить новый конструктор template <typename T> Bar(T) в заголовке и реализовать как template <> Bar::Bar(Tupple) {}

0 голосов
/ 13 сентября 2011

Вы можете зарегистрировать конвертер from-python, который создаст экземпляр Bar из произвольного объекта. См. здесь и мой собственный пример (преобразует либо (Vector3,Quaternion) кортеж, либо 7 * двойной кортеж в 3d преобразование Se3) здесь .

Обратите внимание, что логика состоит из двух шагов: сначала вы определяете, является ли объект конвертируемым (convertible; в вашем случае вы проверяете, является ли он последовательностью и имеет ли правильное количество элементов), затем construct вызывается метод, который фактически возвращает экземпляр, выделенный указателем, переданным в качестве параметра.

Преобразователь должен быть зарегистрирован в BOOST_PYTHON_MODULE. Поскольку реестр конвертера является глобальным, после регистрации он будет использоваться везде автоматически. Все аргументы функций типа Bar или const Bar& должны обрабатываться очень хорошо (и точно не в Bar& от макушки головы).

0 голосов
/ 13 сентября 2011

Вы можете создать статический метод фабрики и затем представить его как один из конструкторов Python для класса. Просто сделайте конвертер, который будет принимать любой объект Python, и вы можете делать все, что пожелаете.

using namespace boost::python;

Bar CreateBar(object obj)
{
    // Do your thing here

    return Bar;
}

// ..................

class_<Bar>("Bar")
    // .....................
    .def("__init__", make_constructor(&CreateBar))
    //.............
    ;
0 голосов
/ 11 декабря 2009

Вы можете экспортировать функцию do_that, которая принимает boost :: python :: object param, проверить, является ли param кортежом python, извлечь данные и передать их объекту.

0 голосов
/ 10 августа 2009

Создайте некоторый тип TupleCollector с переопределенным «оператором (int)», чтобы вы могли написать

f.do_that((TuppleCollector(), 1, 2, 3))

наконец, создайте преобразование между TupleCollector и ожидаемой целью

...