通过 Boost.Python 公开 boost::optional<T> 作为内部参考或 None
Exposing boost::optional<T> via Boost.Python as internal reference or None
我正在通过 Boost.Python 公开我的 C++ classes。我的目的是公开具有内部引用的用户定义 class 类型的成员变量。在我决定引入类型为 boost::optional.
的成员变量之前,这一直很好用
有几篇很棒的帖子展示了如何按值将 boost::optional 公开为 return。具体来说,我实现了this converter。我的代码的其他相关部分如下所示:
struct Bar {}
struct Foo {
boost::optional<Bar> bar;
}
BOOST_PYTHON_MODULE(mymodule) {
using namespace boost::python;
python_optional<Bar>(); //registering the converter
class_<Foo>("Foo")
.add_property ( "bar", make_getter(&Foo::bar, return_value_policy<return_by_value>()), make_setter(&Foo::bar) )
;
}
我试图用 return_value_policy<reference_existing_object>()
或 return_internal_reference<>()
替换 return_value_policy<return_by_value>()
。两者都产生了 Python TypeError:
>> import mymodule
>> foo = mymodule.Foo()
>> bar = foo.bar
TypeError: No Python class registered for C++ class boost::optional<Bar>
我的理解是,我现在正在获取对 boost::optional 对象的引用。但是,我注册的转换器未被调用,因为它需要一个 boost::optional 对象而不是对此类对象的引用。我考虑过更换转换器,但我是新手,我真的不知道该怎么做。有什么建议吗?
我通过向 struct Foo
添加 getter 找到了解决方法,即 returns 指向 boost::optional 持有的对象的指针或 [= 情况下的 nullptr 29=]。由于 &*bar
returns const Bar*
我不得不使用 const_cast
.
struct Bar {}
struct Foo {
Bar* getBar() { return (bar ? const_cast<Bar*>(&*bar) : nullptr); };
boost::optional<Bar> bar;
}
BOOST_PYTHON_MODULE(mymodule) {
using namespace boost::python;
python_optional<Bar>(); //registering the converter
class_<Foo>("Foo")
.add_property ( "bar", make_function(static_cast< Bar*(Foo::*)() >(&Foo::getBar), return_internal_reference<>() ), make_setter(&Foo::bar) )
;
}
如果 bar
属于 Foo
的基数 class Python 将产生这样的 ArgumentError:
>> import mymodule
>> foo = mymodule.Foo()
>> foo.bar = mymodule.Bar()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument tpyes in
None.None(Foo, Bar)
did not match C++ signature:
None(FooBase {lvalue}, boost::optional<Bar>)
为了解决这个问题,在classFoo
.
中为bar
定义一个getter和一个setter
struct Bar {}
struct FooBase {
boost::optional<Bar> bar;
}
struct Foo : public FooBase {
Bar* getBar() { return (bar ? const_cast<Bar*>(&*bar) : nullptr); };
void setBar(const Bar* bar) { bar ? this->bar = *bar : this->bar = boost::none; }
}
void (Foo::*foo_bar_set)(const Bar*) = &Foo::setBar;
BOOST_PYTHON_MODULE(mymodule) {
using namespace boost::python;
python_optional<Bar>(); //registering the converter
class_<Foo>("Foo")
.add_property ( "bar", make_function(static_cast< Bar*(Foo::*)() >(&Foo::getBar), return_internal_reference<>() ), foo_bar_set )
;
}
我正在通过 Boost.Python 公开我的 C++ classes。我的目的是公开具有内部引用的用户定义 class 类型的成员变量。在我决定引入类型为 boost::optional
有几篇很棒的帖子展示了如何按值将 boost::optional
struct Bar {}
struct Foo {
boost::optional<Bar> bar;
}
BOOST_PYTHON_MODULE(mymodule) {
using namespace boost::python;
python_optional<Bar>(); //registering the converter
class_<Foo>("Foo")
.add_property ( "bar", make_getter(&Foo::bar, return_value_policy<return_by_value>()), make_setter(&Foo::bar) )
;
}
我试图用 return_value_policy<reference_existing_object>()
或 return_internal_reference<>()
替换 return_value_policy<return_by_value>()
。两者都产生了 Python TypeError:
>> import mymodule
>> foo = mymodule.Foo()
>> bar = foo.bar
TypeError: No Python class registered for C++ class boost::optional<Bar>
我的理解是,我现在正在获取对 boost::optional
我通过向 struct Foo
添加 getter 找到了解决方法,即 returns 指向 boost::optional 持有的对象的指针或 [= 情况下的 nullptr 29=]。由于 &*bar
returns const Bar*
我不得不使用 const_cast
.
struct Bar {}
struct Foo {
Bar* getBar() { return (bar ? const_cast<Bar*>(&*bar) : nullptr); };
boost::optional<Bar> bar;
}
BOOST_PYTHON_MODULE(mymodule) {
using namespace boost::python;
python_optional<Bar>(); //registering the converter
class_<Foo>("Foo")
.add_property ( "bar", make_function(static_cast< Bar*(Foo::*)() >(&Foo::getBar), return_internal_reference<>() ), make_setter(&Foo::bar) )
;
}
如果 bar
属于 Foo
的基数 class Python 将产生这样的 ArgumentError:
>> import mymodule
>> foo = mymodule.Foo()
>> foo.bar = mymodule.Bar()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Boost.Python.ArgumentError: Python argument tpyes in
None.None(Foo, Bar)
did not match C++ signature:
None(FooBase {lvalue}, boost::optional<Bar>)
为了解决这个问题,在classFoo
.
bar
定义一个getter和一个setter
struct Bar {}
struct FooBase {
boost::optional<Bar> bar;
}
struct Foo : public FooBase {
Bar* getBar() { return (bar ? const_cast<Bar*>(&*bar) : nullptr); };
void setBar(const Bar* bar) { bar ? this->bar = *bar : this->bar = boost::none; }
}
void (Foo::*foo_bar_set)(const Bar*) = &Foo::setBar;
BOOST_PYTHON_MODULE(mymodule) {
using namespace boost::python;
python_optional<Bar>(); //registering the converter
class_<Foo>("Foo")
.add_property ( "bar", make_function(static_cast< Bar*(Foo::*)() >(&Foo::getBar), return_internal_reference<>() ), foo_bar_set )
;
}