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 指向基的共享指针将执行我想要的操作。
但这不是我想要手动执行的操作,因为这是对基本指针转换的微不足道的派生。
所以,经过长时间的调查,我得出的答案是只返回一个指向基的共享指针就可以解决问题。
无论如何,感谢您的帮助。
我正在尝试做一个简单的派生指针到基指针的转换,这在纯 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 指向基的共享指针将执行我想要的操作。
但这不是我想要手动执行的操作,因为这是对基本指针转换的微不足道的派生。
所以,经过长时间的调查,我得出的答案是只返回一个指向基的共享指针就可以解决问题。 无论如何,感谢您的帮助。