使用boost.python为现有库创建python绑定时遇到了问题。方案如下:
#include<boost/python.hpp>
namespace bp = boost::python;
struct Base {
std::stringstream _myString;
Base() { };
Base(const Base& base) { _myString<<base._myString.str(); }
void getString(std::stringstream& some_string) {
_myString.str("");
_myString<<some_string.str();
std::cout<<"Got string: \""<<_myString.str()<<"\""<<std::endl;
}
};
struct BaseWrapper : Base,
bp::wrapper<Base>
{
BaseWrapper() :
Base(),
bp::wrapper<Base>() { };
BaseWrapper(const Base& base) :
Base(base),
bp::wrapper<Base>() { };
void getString(bp::object pyObj) {
std::string strLine = bp::extract<std::string>(pyObj);
std::stringstream sstrLine;
sstrLine<<strLine;
Base::getString(sstrLine);
}
};
struct Derived : Base
{
Derived() : Base() { };
Derived(const Derived& derived) : Base() { _myString<<derived._myString.str(); };
};
struct DerivedWrapper : Derived,
bp::wrapper<Derived>
{
DerivedWrapper() :
Derived(),
bp::wrapper<Derived>() { };
DerivedWrapper(const Derived derived) :
Derived(derived),
bp::wrapper<Derived>() { };
};
BOOST_PYTHON_MODULE(testInheritance){
bp::class_<BaseWrapper>("Base")
.def("getString", &BaseWrapper::getString);
bp::class_<DerivedWrapper, bp::bases<Base> >("Derived");
}
(对不起,长代码块,这是我能想到的最小例子。)
你可以看到我必须覆盖BaseWrapper中的getString()
方法,以便它可以与Python字符串一起工作,这部分工作正常:
>>> import testInheritance
>>> base = testInheritance.Base()
>>> base.getString("bla")
Got string: "bla"
>>>
我尝试从getString
的实例调用Derived
时出现问题:
>>> derived = testInheritance.Derived()
>>> derived.getString("bla")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument types in
Base.getString(Derived, str)
did not match C++ signature:
getString(BaseWrapper {lvalue}, boost::python::api::object)
>>>
我可以理解这里出了什么问题,但我不知道如何解决这个问题。我将不胜感激任何帮助!
最诚挚的问候, eDude
答案 0 :(得分:2)
问题是,DerivedWrapper
与BaseWrapper
没有任何关系。因此DerivedWrapper需要提供自己的python自适应void getString(bp::object pyObj)
的实现。
所以使其成功的一种方法是这样的:
struct DerivedWrapper : Derived,
bp::wrapper<Derived>
{
DerivedWrapper() :
Derived(),
bp::wrapper<Derived>() { };
DerivedWrapper(const Derived derived) :
Derived(derived),
bp::wrapper<Derived>() { };
void getString(bp::object pyObj) {
std::string strLine = bp::extract<std::string>(pyObj);
std::stringstream sstrLine;
sstrLine<<"(from DerivedWrapper) "<<strLine;
Derived::getString(sstrLine);
}
};
[...]
bp::class_<DerivedWrapper, bp::bases<Base> >("Derived")
.def("getString", &DerivedWrapper::getString);
和
的输出base = testInheritance.Base()
base.getString("bla")
derived = testInheritance.Derived()
derived.getString("blub")
符合预期
Got string: "bla"
Got string: "(from DerivedWrapper) blub"
答案 1 :(得分:1)
我遇到的问题与我设法解决的问题完全相同,但在某些特殊情况下,解决方案存在一些内部错误。当需要从boost :: python传递的值创建boost :: weak_ptr引用时,在python中使用boost :: shared_ptr存在一个已知问题。我不会详细介绍与帖子无关的细节。无论如何,我需要将boost :: shared_ptr包装到另一个类(我称之为PythonSharedPtr)来隐藏boost :: python中的boost :: shared_ptr然后我得到类似的问题。考虑以下设置: 类A在c ++端用作boost :: shared_ptr,类B(继承自A)作为boost :: shared_ptr,在python中,shared_ptr都被包装到另一个类中(为了进一步说明我需要创建它的原因,解释如下: boost::python and weak_ptr : stuff disappearing http://mail.python.org/pipermail/cplusplus-sig/2009-November/014983.html
那么我需要为boost python编写适当的导出: class_,wrapped_shared_ptr,noncopyable&gt; 和 class_,wrapped_shared_ptr,noncopyable&gt;
我认为直到现在它与你的代码相似。棘手的部分是如何允许在boost :: python中使用base来导出B(而shared_ptr与shared_ptr无关)。经过对boost :: python源代码的一些研究,并提供了相当不错的解决方案,但它仅适用于案例,B类没有多重继承。
以下是代码:
namespace boost { namespace python { namespace objects
{
template<typename Source, typename Target>
struct shared_ptr_cast_generator
{
static void* execute(void* source)
{
const boost::shared_ptr<Source>* sourcePtr = static_cast<boost::shared_ptr<Source>*>(source);
const boost::shared_ptr<Target> target = boost::dynamic_pointer_cast<Target>(*sourcePtr);
if(reinterpret_cast<size_t>(target.get()) == reinterpret_cast<size_t>(sourcePtr->get()))
return source;
else
{
// assertion which is triggered when multi-inheritance is used for Source type
// in this case it is necessary to create new instance of shared_ptr<Target> but
// it is not possible to make it in-place due to memory leak
assert(!"Wrong cast");
return nullptr;
}
}
};
template<typename Source, typename Target>
struct cast_generator<boost::shared_ptr<Source>, boost::shared_ptr<Target> >
{
typedef shared_ptr_cast_generator<Source, Target> type;
};
}}}
通过提供这样的代码,可以调整第二次导出到python: class_,wrapped_shared_ptr,noncopyable,bases&gt;
请注意存储在执行函数中的转换 - 如果存在Source和Target之间的转换,则返回相同的地址 - 因此如果只是将Source *重新解释为Target *,它必须也是有效的(必须存储两个类中的数据)在完全相同的地方)。
在你的情况下,也许这样的解决方案是不够的,但至少它可以给你一些想法。