通过Boost.Python将boost :: optional <t>公开为内部引用或None

时间:2017-09-20 16:12:41

标签: c++ boost-python boost-optional

我通过Boost.Python公开我的C ++类。我的目的是公开具有内部引用的用户定义类类型的成员变量。这工作正常,直到我决定引入类型为boost :: optional&lt; T&gt;。

的成员变量

有几个很棒的帖子展示了如何公开boost :: optional&lt; T&gt;作为价值回报。具体来说,我已经实施了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<return_by_value>()替换为return_value_policy<reference_existing_object>()return_internal_reference<>()。两者都产生了Python TypeError:

>> import mymodule
>> foo = mymodule.Foo()
>> bar = foo.bar
TypeError: No Python class registered for C++ class boost::optional<Bar>

我的理解是,我现在正在获得对boost :: optional&lt; T&gt;的引用。宾语。然而,我注册的转换器没有被调用,因为它期望一个boost :: optional&lt; T&gt;。对象而不是对这样一个对象的引用。我想改变转换器,但我是新手,我真的不知道如何。有什么建议吗?

1 个答案:

答案 0 :(得分:0)

我通过向struct Foo添加一个getter来找到一种解决方法,该getter返回指向boost :: optional持有的对象的指针,或者在boost :: none的情况下返回nullptr。当&*bar返回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,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>)

要解决此问题,请在班级bar中为Foo定义一个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 )
  ;
}