1

我正在通过 Boost.Python 公开我的 C++ 类。我的目的是公开具有内部引用的用户定义类类型的成员变量。在我决定引入 boost::optional<T> 类型的成员变量之前,这一直很好。

有几篇很棒的文章展示了如何将 boost::optional<T> 公开为按值返回。具体来说,我已经实现了这个转换器。我的代码的其他相关部分如下所示:

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>()or替换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<T> 对象的引用。但是,我注册的转换器没有被调用,因为它需要一个 boost::optional<T> 对象而不是对此类对象的引用。我想过更换转换器,但我是新手,我真的不知道怎么做。有什么建议么?

4

1 回答 1

0

我通过添加一个 getter 找到了一种解决方法,struct Foo它要么返回指向 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属于FooPython 的基类,则会产生这样的 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在 class 中定义一个 getter 和一个 setter Foo

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 )
  ;
}
于 2017-09-21T16:35:51.690 回答