【问题标题】:boost.python exposing members of membersboost.python 暴露成员的成员
【发布时间】:2013-07-29 23:35:49
【问题描述】:

我有以下(简化的)代码:

struct A
{
    int intVal;
    char charVal;
};

struct B
{
    A* someObj;
};

我想公开B::A::intVal,但以下方法不起作用:

class_<B>("someClass")
    .def_readonly("var", &B::A::intVar)
    ;

我该怎么做?

【问题讨论】:

  • 我有时间在下面正确完成答案。我似乎在两种方面都按预期工作。

标签: c++ boost-python


【解决方案1】:

B::A::intVar 不起作用,因为它是一个格式错误的合格 ID。我选择将问题分成两部分:合格 ID 和在 Boost.Python 中公开成员。


以下代码将两个结构体引入同一个命名空间。因此,B::A 的限定 ID 不存在,因为 B 不会重新引入 A 作为嵌套标识符:

struct A
{
  int intVal;
  char charVal;
};

struct B
{
  A* someObj;
};

要在B 中引入A 标识符,B 需要:

  • 包含A 结构的定义。 (即A 成为嵌套结构)。

    struct B
    {
      struct A // introduces B::A
      {
        int intVal;
        char charVal;
      };
      A* someObj;
    };
    
  • A 提供一个typedef。

    struct A
    {
      int intVal;
      char charVal;
    };
    
    struct B
    {
      typedef ::A A; // introduces B::A
      A* someObj;
    };
    

要直接暴露成员的成员,Boost.Python 需要一个简单的辅助函数,例如:

/// @brief Helper function that returns B.someObj.intVal.
int get_b_intval(const B& self)
{
  return self.someObj->intVal;
}

帮助函数可以公开为 Python B::var 只读属性。

namespace python = boost::python;
python::class_<B>("someClass")
  .add_property("var", &get_b_intval)
  ;

这是一个完整的例子:

#include <boost/python.hpp>

struct A
{
  int intVal;
  char charVal;
};

struct B
{
  A* someObj;
};


/// @brief Helper function that returns B.someObj.intVal.
int get_b_intval(const B& self)
{
  return self.someObj->intVal;
}

/// @brief Helper function to create a B object.
B make_B()
{
  static A a;
  a.intVal = 42;
  B b;
  b.someObj = &a;
  return b;
}

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<B>("someClass")
    .add_property("var", &get_b_intval)
    ;

  python::def("make_B", &make_B);
}

及其用法:

>>> import example
>>> b = example.make_B()
>>> print b.var
42
>>> b.var = 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

【讨论】:

    【解决方案2】:

    我假设您以某种方式填写了B::someObj,或者访问可能是随机的指针会使您的代码崩溃。鉴于这种情况,您必须同时公开 A 和 B 以通过 B 访问 A。我测试了以下代码,它可以按预期编译和工作:

    #include <boost/python.hpp>
    #include <boost/shared_ptr.hpp>
    
    struct A
    {
      int intVal;
      char charVal;
    };
    
    struct B
    {
      A* someObj;
    };
    
    static boost::shared_ptr<B> create_b() {
      boost::shared_ptr<B> retval(new B);
      retval->someObj = new A; //<< WARNING: leakage ahead
      retval->someObj->intVal = 3;
      retval->someObj->charVal = 'a';
      return retval;
    }
    
    BOOST_PYTHON_MODULE(test)
    {
      using namespace boost::python;
    
      class_<A, A* >("A")
        .def_readonly("intVal", &A::intVal)
        .def_readonly("charVal", &A::charVal)
        ;
    
      class_<B, boost::shared_ptr<B> >("B")
        .def("__init__", make_constructor(&create_b))
        .def_readonly("someObj", &B::someObj)
        ;
    }
    

    我的个人提示:如果您可以访问B 的定义,请将访问指针从B 更改为A 以使用boost::shared_ptr&lt;A&gt;。 Boost.Python 可以优雅地处理这个问题并正确地引用计数。在这种情况下,您的代码将如下所示:

    #include <boost/python.hpp>
    #include <boost/shared_ptr.hpp>
    
    struct A
    {
      int intVal;
      char charVal;
    };
    
    struct B
    {
      boost::shared_ptr<A> someObj;
    };
    
    static boost::shared_ptr<B> create_b() {
      boost::shared_ptr<B> retval(new B);
      retval->someObj.reset(new A); //< no more leaks
      retval->someObj->intVal = 3;
      retval->someObj->charVal = 'a';
      return retval;
    }
    
    BOOST_PYTHON_MODULE(test)
    {
      using namespace boost::python;
    
      class_<A, boost::shared_ptr<A> >("A")
        .def_readonly("intVal", &A::intVal)
        .def_readonly("charVal", &A::charVal)
        ;
    
      class_<B, boost::shared_ptr<B> >("B")
        .def("__init__", make_constructor(&create_b))
        .def_readonly("someObj", &B::someObj)
        ;
    }
    

    在linux下,你可以这样编译和测试这个模块:

    $ g++ -I/usr/include/python2.7 -shared -fpic test.cc -lboost_python -lpython2.7 -o test.so
    

    运行 Python 并检查您的代码是否正常工作:

    >>> import test
    >>> b = test.B()
    >>> b.someObj.intVal
    3
    >>> b.someObj.charVal
    'a'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多