Boost.Python - 如何重新进入模块作用域?

1 投票
1 回答
1903 浏览
提问于 2025-04-17 17:36

我正在把一些C++类暴露给Python,这些类里面有嵌套的enum。我查看了boost.orgwiki.python.org上的示例文档,但我找不到如何在进入一个作用域后再返回到全局或模块作用域的方法。每个后续的作用域都嵌套在前一个作用域里面。

举个例子:

#include <boost/python.hpp>

class Foo
{
public:
    enum Choose { eFoo, eBar };

    /* Default constructor with enum as required argument */
    Foo(Choose choice): m_choice(choice) {}
    ~Foo() {}

    Choose get() const { return m_choice; }

private:
    const Choose m_choice;

};


class Bar
{
};

BOOST_PYTHON_MODULE(foo)
{
    using namespace boost::python;
    scope global;

    /* Define Foo class, and a scope to go with it. */
    scope in_Foo = class_<Foo>
        ("Foo", init<Foo::Choose>())
        .def("rovalue", &Foo::get)
        ;

    /* Expose 'Choose' enum as Foo.Choose */
    enum_<Foo::Choose>("Choose")
        .value("Foo", Foo::eFoo)
        .value("Bar", Foo::eBar)
        ;

    /* How to get back to module scope??  */
    global;
    scope();

    /* This currently is exposed as Foo.Bar, but should just be Bar */
    class_<Bar>("Bar", init<>())
        ;
}

我尝试把那行global;改成各种不同的东西,但结果都是一样的:

$ g++ -fPIC -shared scope.cpp -o foo.so -lpython2.7 -I/usr/include/python2.7 -lboost_python
$ python -c 'import foo; print "Bar" in dir(foo)'
False
$ python -c 'import foo; print "Bar" in dir(foo.Foo)'
True

编辑:

我又看了一下wiki.python.org,似乎在上面的例子中,正确的做法是使用scope within(global)来返回到模块级别的作用域。确实,这在上面的例子中有效。不过不幸的是,当我在实际应用中使用它时,却出现了编译错误。

#include <boost/python.hpp>
using namespace boost;
BOOST_PYTHON_MODULE(foo)
{
    python::scope module_level;
    /* .... */
    python::scope python::within(module_level);
    /* ... */
}

编译错误:

error: invalid use of qualified-name 'boost::python::within'

1 个回答

5

有点讽刺的是,这个功能可能太聪明了,实际上可以通过C++的作用域来实现。boost::python::scope的文档提到,当一个scope对象的生命周期结束时,当前的作用域会恢复到在这个scope对象被创建之前的状态。

BOOST_PYTHON_MODULE(foo)              // set scope to foo
{
  using namespace boost::python;
  {
    scope in_Foo = class_<Foo>        // define foo.Foo and set scope to foo.Foo
        ("Foo", init<Foo::Choose>())
        .def("rovalue", &Foo::get)
        ;

    enum_<Foo::Choose>("Choose")     // define foo.Foo.Choose
        .value("Foo", Foo::eFoo)
        .value("Bar", Foo::eBar)
        ;
  }                                  // revert scope, setting scope to foo

  class_<Bar>("Bar", init<>())       // define foo.Bar
      ;
}

虽然scope对象的生命周期可以通过其他方式来管理,但我发现将scope对象作为自动变量放在C++的作用域中,能和C++的命名空间有些相似之处。

撰写回答