Boost Python возвращает ссылку на входной параметр cast, не работающий с виртуальной функцией - PullRequest
0 голосов
/ 06 ноября 2018

Я обертываю шаблоны классов A и B через boost python и пытаюсь привести их между собой. Я реализую функцию toB и обертываю ее return_internal_reference <> для достижения этой цели. Однако он не возвращает объект B в python, но возвращает «мертвый» объект A, функция-член которого больше не может использоваться.

Я сужаю проблему - это виртуальная функция в базовом классе, Bar. Функция toB правильно возвращает объект B, ссылающийся на объект A, если я удаляю виртуальное ключевое слово для hi (). Но как правильно это сделать? Почему виртуальная функция в базовом классе влияет на результат? С другой стороны, есть ли способ привести классы обёртывания Boost Python непосредственно в Python?

#include <boost/python.hpp>
#include <iostream>
using namespace boost::python;

struct Bar
{
  virtual void hi() { std::cout << "Hi Bar." << std::endl; }
  virtual ~Bar() {}
};

template<typename T>
struct Foo : Bar
{
  void set(T v) { val = v; }
  T get() { return val; }
private:
  T val;
};

using A = Foo<unsigned short>;
using B = Foo<short>;

B & toB(A & a) { return *reinterpret_cast<B*>(&a);}

BOOST_PYTHON_MODULE(example)
{
  class_<A>("A")
    .def("set", &A::set)
    .def("get", &A::get)
  ;
  class_<B>("B")
    .def("set", &B::set)
    .def("get", &B::get)
  ;
  def("toB", &toB, return_internal_reference<>());
}


Выполнение Python

>>> from example import *
>>> a = A()
>>> toB(a)
<example.A object at 0x7f7139cd27c0>
>>> toB(a).get()
Traceback (most recent call last):
  File "<stdin>", line 1 in <module>
Boost.Python.ArgumentError: Python argument types in 
    A.get(A)
did not match C++ signature:
    get(Foo<unsigned int> {lvalue})


Это хорошо работает, если я удалю виртуальные ключевые слова в Bar.

struct Bar
{
  void hi() { std::cout << "Hi Bar." << std::endl; }
};

1012 *
*

>>> from example import *
>>> a = A()
>>> toB(a)
<example.B object at 0x7f511000c7c0>
>>> toB(a).get()
>>> 4.484155085839415e-44

1 Ответ

0 голосов
/ 08 ноября 2018

Открытые классы A и B не предоставляют всю необходимую информацию об их структуре для python. В частности, что они происходят от класса Bar. Чтобы решить эту проблему, выставьте также класс Bar для python и сообщите Boost.Python об отношениях наследования между Bar и A и между Bar и B:

BOOST_PYTHON_MODULE(example)
{
  class_<Bar>("Bar")
    .def("hi", &Bar::hi)
  ;
  class_<A, bases<Bar>>("A")
    .def("set", &A::set)
    .def("get", &A::get)
  ;
  class_<B, bases<Bar>>("B")
    .def("set", &B::set)
    .def("get", &B::get)
  ;
  def("toB", &toB, return_internal_reference<>());
}

После этого все должно работать как положено:

>>> from example import *
>>> a=A()
>>> b=toB(a)
>>> b.get()
0
...