我已经遇到了Boost.Python的边缘情况,看起来它应该可以工作但不会。
我所拥有的是Base和Derived类,我将其存储在python端的std::shared_ptr
中。我想要做的是将派生类型shared_ptr
传递给通过引用接受基础shared_ptr
的函数。
我做了一些研究并了解了implicitly_convertible,并试图用它来解决问题,但没有成功(虽然它在其他一些情况下确实有帮助)。将Derived传递给接受Base&amp ;;的功能。适用于此但如果它们被shared_ptr
包裹,那么它就会失败。
我目前得到的信息如下:
Boost.Python.ArgumentError: Python argument types in
test_bed_bindings.acceptBaseSharedPtrRef(Derived) did not match C++ signature:
acceptBaseSharedPtrRef(std::shared_ptr<(anonymous namespace)::Base> {lvalue})
请参阅下面的示例代码:
C ++绑定代码
#define BOOST_PYTHON_STATIC_LIB
#define BOOST_PYTHON_USE_GCC_SYMBOL_VISIBILITY 1
#include <boost/optional.hpp>
#include <boost/python.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
#include <memory>
namespace
{
class Base
{
};
class Derived : public Base
{
};
std::shared_ptr<Base> getBaseSharedPtr()
{
auto retVal = std::make_shared<Base>();
std::cout << "Creating Base shared_ptr - " << retVal.get() << std::endl;
return retVal;
}
std::shared_ptr<Derived> getDerivedSharedPtr()
{
auto retVal = std::make_shared<Derived>();
std::cout << "Creating Derived shared_ptr - " << retVal.get() << std::endl;
return retVal;
}
void acceptBaseSharedPtrRef(std::shared_ptr<Base>& base)
{
std::cout << "acceptBaseSharedPtrRef() with " << base.get() << std::endl;
}
void acceptBaseSharedPtrConstRef(const std::shared_ptr<Base>& base)
{
std::cout << "acceptBaseSharedPtrConstRef() with " << base.get() << std::endl;
}
void acceptBaseSharedPtrCopy(std::shared_ptr<Base> base)
{
std::cout << "acceptBaseSharedPtrCopy() with " << base.get() << std::endl;
}
//
void acceptBaseRef(Base base)
{
}
} // namespace
namespace bindings
{
BOOST_PYTHON_MODULE(test_bed_bindings)
{
PyEval_InitThreads();
Py_Initialize();
using namespace boost::python;
def("getBaseSharedPtr", &::getBaseSharedPtr);
def("getDerivedSharedPtr", &::getDerivedSharedPtr);
def("acceptBaseSharedPtrRef", &::acceptBaseSharedPtrRef);
def("acceptBaseSharedPtrConstRef", &::acceptBaseSharedPtrConstRef);
def("acceptBaseSharedPtrCopy", &::acceptBaseSharedPtrCopy);
def("acceptBaseRef", &::acceptBaseRef);
class_<Base, std::shared_ptr<Base> >("Base")
.def(init<>())
;
class_<Derived, bases<Base>, std::shared_ptr<Derived> >("Derived")
.def(init<>())
;
implicitly_convertible<Derived, Base>();
implicitly_convertible<std::shared_ptr<Derived>, std::shared_ptr<Base>>();
} // BOOST_PYTHON
} // namespace bindings
Python执行代码
import test_bed_bindings
baseObj = test_bed_bindings.Base()
derivedObj = test_bed_bindings.Derived()
test_bed_bindings.acceptBaseRef( baseObj )
test_bed_bindings.acceptBaseRef( derivedObj )
baseSharedPtr = test_bed_bindings.getBaseSharedPtr()
derivedSharedPtr = test_bed_bindings.getDerivedSharedPtr()
test_bed_bindings.acceptBaseSharedPtrCopy( baseSharedPtr )
test_bed_bindings.acceptBaseSharedPtrCopy( derivedSharedPtr )
test_bed_bindings.acceptBaseSharedPtrConstRef( baseSharedPtr )
test_bed_bindings.acceptBaseSharedPtrConstRef( derivedSharedPtr )
test_bed_bindings.acceptBaseSharedPtrRef( baseSharedPtr )
test_bed_bindings.acceptBaseSharedPtrRef( derivedSharedPtr )
示例输出
Creating Base shared_ptr - 0x276fdb8
Creating Derived shared_ptr - 0x276fde8
acceptBaseSharedPtrCopy() with 0x276fdb8
acceptBaseSharedPtrCopy() with 0x276fde8
acceptBaseSharedPtrConstRef() with 0x276fdb8
acceptBaseSharedPtrConstRef() with 0x276fde8
acceptBaseSharedPtrRef() with 0x276fdb8
Traceback (most recent call last):
File "test_script.py", line 21, in <module>
test_bed_bindings.acceptBaseSharedPtrRef( derivedSharedPtr )
Boost.Python.ArgumentError: Python argument types in
test_bed_bindings.acceptBaseSharedPtrRef(Derived)
did not match C++ signature:
acceptBaseSharedPtrRef(std::shared_ptr<(anonymous namespace)::Base> {lvalue})
答案 0 :(得分:3)
这是故意的。为了减少悬空引用的可能性并在语言之间提供明确的方向性,Boost.Python将通过const引用向函数传递 rvalue 转换产生的临时对象。 implicit_convertible<Source, Target>
函数在Python转换中注册 rvalue 。由于转换器的结果是 rvalue ,因此只能通过值或常量引用接受它。
当通过boost::python::class_<T, HeldType, Bases>
注册课程时,HeldType
正在包裹T
:
HeldType
T
的实例注册到Python转换器到Python类的实例T
的实例HeldType
的实例注册到Python转换器到Python对象HeldType
的实例Bases
中的每个基类,将来自Python转换器的 lvalue 注册到Python类的实例到基础中T
的实例(不是基数{{1} }})HeldType
中的每个多态基,从基数持有的Bases
实例注册到Python转换器到Python类使用以下设置:
T
以下 lvalue from-Python转换是可能的,因为Python对象包含C ++对象的实例:
class base {};
class derived: public base {};
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<base, std::shared_ptr<base>>("Base");
python::class_<derived, python::bases<base>,
std::shared_ptr<derived>>("Derived");
python::implicitly_convertible<std::shared_ptr<derived>,
std::shared_ptr<base>>();
}
至example.Base
,base
,base&
,const base&
,std::shared_ptr<base>
和std::shared_ptr<base>&
const std::shared_ptr<base>&
至example.Derived
,base
,base&
,const base&
,derived
,derived&
,const derived&
,std::shared_ptr<derived>
和std::shared_ptr<derived>&
以下的to-Python转换是可能的:
const std::shared_ptr<derived>&
或base
至std::shared_ptr<base>
example.Base
或derived
至std::shared_ptr<derived
如果example.Derived
是多态的,则可以进行以下to-Python转换:
base
且静态类型为derived*
至base*
的对象example.Derived
持有std::shared_ptr<base>
到derived
由于example.Derived
明确注册,因此可以进行以下 rvalue 转换:
implicitly_convertible
至example.Derived
和std::shared_ptr<base>
lvalue 和 rvalue 转换之间的区别在于目标C ++对象是否已存在并且是否保存在Python对象中。例如,const std::shared_ptr<base>&
到example.Derived
的左值转换是可能的,因为base&
包含example.Derived
的实例,即derived
}。另一方面,从base
到example.Derived
的左值转换是不可能的,因为std::shared_ptr<base>&
拥有example.Derived
的实例,该实例不会继承来自std::shared_ptr<derived>
。因此,构造具有未指定生存期的std::shared_ptr<base>
并将其作为 rvalue 参数传递给公开函数。
以下是这些转换的完整示例demonstrating:
std::shared_ptr<base>
交互式使用:
#include <boost/python.hpp>
#include <memory> // std::shared_ptr
class base {};
class derived: public base {};
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
python::class_<base, std::shared_ptr<base>>("Base");
python::class_<derived, python::bases<base>,
std::shared_ptr<derived>>("Derived");
python::implicitly_convertible<std::shared_ptr<derived>,
std::shared_ptr<base>>();
python::def("base_value", +[](base){});
python::def("base_ref", +[](base&){});
python::def("base_cref", +[](const base&){});
python::def("shared_base_value", +[](std::shared_ptr<base>){});
python::def("shared_base_ref", +[](std::shared_ptr<base>&){});
python::def("shared_base_cref", +[](const std::shared_ptr<base>&){});
python::def("derived_value", +[](derived){});
python::def("derived_ref", +[](derived&){});
python::def("derived_cref", +[](const derived&){});
python::def("shared_derived_value", +[](std::shared_ptr<derived>){});
python::def("shared_derived_ref", +[](std::shared_ptr<derived>&){});
python::def("shared_derived_cref", +[](const std::shared_ptr<derived>&){});
}