Так что мне удалось заставить это работать, используя конвертер результатов :
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");