Изменение сигнатуры чисто виртуальной функции в boost :: python - PullRequest
0 голосов
/ 07 апреля 2019

У меня есть иерархия C ++, которую мне нужно отразить в python. Базовый класс состоит из пары статических функций, ряда чисто виртуальных функций и ряда простых общедоступных функций с реализациями по умолчанию. Многие из этих методов могут использовать неконстантные ссылки для возврата значений в списке параметров. Реализуя это питоническим способом, я хотел бы вернуть те же значения, что и кортеж. Возможно ли это?

Этот вопрос очень похож на нерешенный вопрос Ускорение Python, оборачивающее виртуальный метод , за исключением того, что рассматриваемые функции являются чисто виртуальными и изменяют как параметры, так и возвращаемые значения.

class Driver_comm
{
public:

   Driver_comm() {};
   virtual ~Driver_comm() {};

   // -------------------------------------------------------------------------
   virtual bool Enumerate_devices(const uint32_t vendor_id,
      uint32_t &n_devices,
      std::string &details) = 0;
};

class Driver_sim : public Driver_comm
{
public:
   Driver_sim() {}
   ~Driver_sim() {}

   // -------------------------------------------------------------------------
   Driver_sim(const Driver_sim& r) = delete;

   // -------------------------------------------------------------------------
   const Driver_sim& operator=(const Driver_sim& r) = delete;

   // -------------------------------------------------------------------------
   bool Enumerate_devices(const uint32_t,
      uint32_t &n_devices,
      std::string &) override {
      n_devices = 1; return true;
   }
};

// ============================================================================

using namespace boost::python;

BOOST_PYTHON_MODULE(example)
{
   struct Comm_wrapper : public Driver_comm, public wrapper<Driver_comm>
   {
      tuple enumerate_devices(const uint32_t vendor_id)
      {
         uint32_t n_devices;
         std::string details;
         bool ok = false;
         override f_enumerate = this->get_override("Enumerate_devices");
         if (f_enumerate)
         {
            ok = f_enumerate(vendor_id, n_devices, details);
         }
         else
         {
            printf("override = None");
         }
         return make_tuple(ok, n_devices, details.c_str());
      }
   };

   class_<Comm_wrapper, boost::noncopyable>("driver_comm", no_init)
      .def("Enumerate_devices", (&Comm_wrapper::enumerate_devices))
      ;

   class_<Driver_sim, boost::noncopyable, bases<Driver_comm> >("driver_sim", init<>())
      ;
}

Звонок

    n_devices = 0
    result = ""
    ok, n_devices, result = d.Enumerate_devices(0x1010)

приводит к ошибке "не соответствует сигнатуре C ++".

    Python argument types in driver_comm.Enumerate_devices(driver_sim, int)
did not match C++ signature:
    Enumerate_devices(struct `void __cdecl init_module_example(void)'::`2'::Comm
_wrapper {lvalue}, unsigned int)

При добавлении реализации по умолчанию к оболочке, как предложено в *, 1015 * не удается создать из-за несоответствия типа функции:

error C2664: 'void boost::python::detail::error::not_a_derived_class_member<Default>(Default)' : cannot convert argument 1 from 'bool (__cdecl Driver_comm::* )(uint32_t,uint32_t &,std::string &)' to 'boost::python::tuple (__cdecl init_module_example::Comm_wrapper::* )(uint32_t)'

Любое объяснение приветствуется. Если бы у pybind11 (или другого инструмента) был лучший способ решить эту проблему, я был бы рад развлечь его.

...