boost::python::extract 提取共享基指针失败

boost::python::extract fails to extract shared base pointer

我正在尝试做一个简单的派生指针到基指针的转换,这在纯 C++ 中是正常行为。
但是,处理 boost::python,要在 python 到 C++ 的转换过程中获得相同的行为,提取步骤会失败。 Boost::python::extract 无法从共享派生指针中提取共享基指针。
这是来源:

#include <iostream>
#include <vector>
#include <string>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/python.hpp>

namespace bp = boost::python;

class A {
    public:
        A() : m_int(10) { }
        A(int numb) : m_int(numb) { }
        int get_m() const { return m_int; }
        virtual ~A() {}
    private:
        int m_int;
};

class B: public A {
    public:
        B() : A(100) {}
};

using BPtr = boost::shared_ptr<B>;
using APtr = boost::shared_ptr<A>;
using AContainer = std::vector<APtr>;
using AContainerPtr = boost::shared_ptr<AContainer>;

std::ostream& operator<<(std::ostream& out, const A& obj) {
    out << obj.get_m();
    return out;
}

APtr CreateA() {
    return boost::make_shared<A>();
}

BPtr CreateB() {
    return boost::make_shared<B>();
}

AContainerPtr CreateEmptyAContainer() {
    return boost::make_shared<AContainer>();
}

void PushBack(const AContainerPtr& cont, const bp::object& obj) {
    bp::extract<const APtr&> a_obj(obj);
    if (a_obj.check()) {
        cont->push_back(a_obj);
    } else {
        std::cerr << "Non A object!!!\n";
    }
}
void ext(const bp::object& iterable) {
    bp::handle<> iter_ptr(PyObject_GetIter(iterable.ptr()));
    PyObject* item_raw_ptr = PyIter_Next(iter_ptr.get());
    bp::handle<> item_ptr(bp::allow_null<>(item_raw_ptr));
    while (item_ptr.get()) {
        bp::extract<const APtr&> ex(item_ptr.get());
        if (ex.check()) {
            std::cout << "APtr extracted!\n";
        } else {
            bp::extract<const BPtr&> ex(item_ptr.get());
            if (ex.check()) {
                std::cout << "BPtr extracted!\n";
            } else {
                std::cout << "Failed to extract!!!\n";
            }
        }
        PyObject* item_raw_ptr = PyIter_Next(iter_ptr.get());
        item_ptr = bp::handle<>(bp::allow_null<>(item_raw_ptr));
    }
}
BOOST_PYTHON_MODULE(example) {
    bp::class_<A, APtr, boost::noncopyable>("A", bp::init<>())
        .def("__init__", bp::make_constructor(CreateA))
        .def(bp::self_ns::str(bp::self))
        ;

    bp::class_<B, bp::bases<A>, BPtr, boost::noncopyable>("B", bp::init<>())
        .def("__init__", bp::make_constructor(CreateB))
        ;

    bp::class_<AContainer, AContainerPtr, boost::noncopyable>("AContainer", bp::no_init)
        .def("__init__", bp::make_constructor(CreateEmptyAContainer))
        .def("__iter__", bp::iterator<AContainer>())
        .def("__len__", &AContainer::size)
        .def("append", PushBack)
        ;
    bp::def("ext", ext);
    bp::implicitly_convertible<BPtr, APtr>();
}

在 linux 上使用 gcc(g++ (GCC) 5.2.0) 编译它并在 Python 中以这种方式使用它:

#!/usr/bin/env python

import example
b = example.B()
print b                         # 100
print type(b)                   # <class 'example.B'>
print isinstance(b, example.B)  # True
print isinstance(b, example.A)  # True
l = [b]
example.ext(l)                  # BPtr extracted!

cont = example.AContainer()
cont.append(b)                  # Non A object!!!

我得到的结果显示在评论中。尽管期望 "APtr extracted!" 打印在 example.ext([b]) 函数调用上,而不是通过将 "b" 放入 cont.[=30= 来抱怨 const.append() 函数调用]

即使添加 implicitly_convertible<>() 也无济于事。

能否请您具体说明在这种情况下做错了什么?

我尝试在网上冲浪这个问题,但实际上在所有情况下派生 class 都定义在 python 中,解决方案是调用 super().init函数。

编辑
我知道将 CreateB() 函数 (constructor) 的 return 值更改为 return 指向基的共享指针将执行我想要的操作。
但这不是我想要手动执行的操作,因为这是对基本指针转换的微不足道的派生。

所以,经过长时间的调查,我得出的答案是只返回一个指向基的共享指针就可以解决问题。 无论如何,感谢您的帮助。