在boostpython中使用共享指针自动下传返回值

问题描述 投票:0回答:1

我想知道,在python中,是否有办法将 "downcasted "对象作为函数的结果,使用 boost::python,同时使用共享指针。考虑以下场景。

class A {
    virtual ~A() { }
};

class B: public A {
    std::shared_ptr<B> makeB() { return std::make_shared<B>(); }
    std::shared_ptr<A> f(bool b) { return b ? std::make_shared<B>() : std::make_shared<A>();
};


BOOST_PYTHON_MODULE(module) {

    using namespace boost::python;

    register_ptr_to_python<std::shared_ptr<A>>();
    register_ptr_to_python<std::shared_ptr<B>>();

    class_<A, std::shared_ptr<A>, boost::noncopyable>("A", no_init);

    class_<B, bases<A>, boost::noncopyable>("B", no_init)
        .def("f", &B::f)
        .def("makeB", &B::makeB).staticmethod("makeB");

}

现在在python中,我可以检索一个 B 对象并调用 f 但所产生的对象将被看作是一个 A 对象。

import module

b = module.B.makeB()
type(b)  # This is module.B

u = b.f(true)
type(u)  # This is always module.A

无论如何动态地返回一个类型的对象。B 在python中,我必须手动下传,这没关系,因为在C++中很常见,但在python中,我希望能有动态的返回类型。在C++中,我必须手动downcast,这是好的,因为它在C++中很常见,但在python中,我希望能有一个动态的返回类型。

c++ boost boost-python
1个回答
0
投票

所以我设法用一个 结果转换器:

template <class FromType, class ToType>
struct DowncastReturn {

  template <class T>
  struct apply;

  template <>
  struct apply<std::shared_ptr<FromType>> {
    struct type {

      bool convertible() const { return true;  }

      inline PyObject* operator()(std::shared_ptr<FromType> p) const {
        if (p == nullptr) {
          return bpy::detail::none();
        }
        else {
          auto downcast_p = std::dynamic_pointer_cast<ToType>(p);
          bpy::object p_value = downcast_p == nullptr ? bpy::object{ p } : bpy::object{ downcast_p };
          return bpy::incref(p_value.ptr());
        }
      }

      inline PyTypeObject const* get_pytype() const {
        return bpy::converter::registered_pytype<FromType>::get_pytype();
      }

    };
  };
};

那么就可以使用这个。

class_<B, bases<A>, boost::noncopyable>("B", no_init)
        .def("f", &B::f, return_value_policy<DowncastReturn<A, B>>())
        .def("makeB", &B::makeB).staticmethod("makeB");

这比我的第一个版本需要更多的设置 但如果多个方法都需要这个的话,就更容易使用了。


第一个版本。

这是我的第一个版本的答案,我没有依靠一个新的系统,而是手动完成了下传。return_value_policy. 这个想法很简单,就是把返回的对象手动包装成一个叫做 boost::python::object:

class_<B, bases<A>, boost::noncopyable>("B", no_init)
        .def("f", +[](B *self, bool b) { 
            auto *r = self->f();
            auto *rb = dynamic_cast<B*>(r);  
            return rb == nullptr ? object{ r } : object{ rb };
        })
        .def("makeB", &B::makeB).staticmethod("makeB");
© www.soinside.com 2019 - 2024. All rights reserved.