【问题标题】:Exposing boost::optional<T> via Boost.Python as internal reference or None通过 Boost.Python 公开 boost::optional<T> 作为内部引用或 None
【发布时间】:2017-09-20 16:12:41
【问题描述】:

我正在通过 Boost.Python 公开我的 C++ 类。我的目的是公开具有内部引用的用户定义类类型的成员变量。在我决定引入 boost::optional.

类型的成员变量之前,这一直很好。

有几篇很棒的文章展示了如何将 boost::optional 公开为按值返回。具体来说,我已经实现了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&lt;return_by_value&gt;() 替换为return_value_policy&lt;reference_existing_object&gt;()return_internal_reference&lt;&gt;()。两者都产生了 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 对象而不是对此类对象的引用。我考虑过更换转换器,但我是新手,我真的不知道怎么做。有什么建议吗?

【问题讨论】:

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


    【解决方案1】:

    我找到了一种解决方法,方法是向struct Foo 添加一个getter,它要么返回指向boost::optional 持有的对象的指针,要么在boost::none 的情况下返回一个nullptr。由于&amp;*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>)
    

    为了解决这个问题,在 Foo 类中为 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 )
      ;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-06
      相关资源
      最近更新 更多