Boost.Python中的C ++静态

时间:2014-05-06 09:14:29

标签: c++ boost-python

我有一个C ++类,它包含某种“静态”(在这种特殊情况下为“m_engine”):

class RndGenerator
{
public:
  static void setInitialSeed(unsigned int seed);
  static unsigned int rndNumber();
  ...
private:
  ...
  RndGenerator();
  static std::mt19937 m_engine;
};

这个类在我的项目中广泛使用,在C ++级别。

通过Boost.Python公开RndGenerator后:

class_<RndGenerator, boost::noncopyable>("RndGenerator", no_init)
  .def("setInitialSeed", &RndGenerator::setInitialSeed)
  .staticmethod("setInitialSeed")
  .def("rndNumber", &RndGenerator::rndNumber)
  .staticmethod("rndNumber")
  ;

我希望有可能从Python级别设置初始种子:

 RndGenerator.setInitialSeed(1234)

我希望,在这一行之后,在C ++级别上所有对RndGenerator :: rndNumber()的调用都会考虑到指定的初始种子(1234)。 但事实并非如此。

包含暴露给Python的静态成员的类是否有任何问题? 或者我的问题与RndGenerator的类似单身的性质有关吗?

2 个答案:

答案 0 :(得分:3)

Boost.Python在暴露的C ++类上使用静态数据成员或静态成员函数应该没有问题。这可能是假阳性吗?或者,对于在多个转换单元中实例化相同模板的更复杂和特定情况,使用动态库,具有相同符号名称的多个静态数据成员实例可以驻留在同一个进程空间中。

无论如何,这是一个完整的示例,演示静态成员函数和静态数据成员在使用Boost.Python公开的类上的预期行为:

#include <boost/python.hpp>

// Basic mockup type.
class spam
{
public:
  static void set_x(unsigned int x) { x_ = x; }
  static unsigned int get_x() { return x_; };
private:
  spam() {};
  spam(const spam&);
  spam& operator=(const spam&);
  static unsigned int x_;
};

unsigned int spam::x_ = 0;

// Auxiliary function.
bool spam_check_x(unsigned int x)
{
  return x == spam::get_x();
}

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<spam, boost::noncopyable>("Spam", python::no_init)
    .def("setX", &spam::set_x)
      .staticmethod("setX")
    .def("getX", &spam::get_x)
      .staticmethod("getX")
    .def("checkX", &spam_check_x)
      .staticmethod("checkX")
    ;
}

交互式使用:

>>> from example import Spam
>>> x = 42
>>> assert(Spam.getX() != x)
>>> assert(not Spam.checkX(x))
>>> Spam.setX(x)
>>> assert(Spam.getX() == x)
>>> assert(Spam.checkX(x))
>>> x = 43
>>> assert(Spam.getX() != x)
>>> assert(not Spam.checkX(x))

答案 1 :(得分:0)

我意识到这是一个老问题,但我最近遇到了同样的问题并认为我应该分享。

通过以下步骤,我们能够使用Boost 1.56在Windows上重现该问题:

  • 在C ++中,创建两个单独的Boost.Python模块:
    • 模块A公开一个函数,用于在类Foo
    • 中设置静态变量
    • 模块B公开了一个访问Foo静态变量的函数
  • 在Python中,调用A的setter,然后调用B的getter。您希望该值匹配,但(至少在我们的例子中)B的静态仍将设置为其默认值。

这只会突破扩展模块边界(单独的.pyd文件)。该问题与Windows上的动态链接行为有关。 Here是一个维基页面,讨论了同一问题的不同表现形式。

我们的解决方案是将C ++模块合并到一个Boost.Python模块中,因此也就是一个共享对象。为了模仿我们的旧设置,我们添加了子模块来维护库之间的分离:

// Put all following definitions in the current scope into a namespace-esque module
#define MAKE_MODULE(modName) \
    boost::python::object module(boost::python::handle<>(boost::python::borrowed(PyImport_AddModule("pymod."#modName)))); \
    scope().attr(#modName) = module; \
    scope s(module);

using namespace boost::python;

BOOST_PYTHON_MODULE(pymod)
{
    object package = scope();
    package.attr("__path__") = "pymod";

    // pymod.a
    {
        MAKE_MODULE(a);
        exportModuleA();
    }

    // pymod.b
    {
        MAKE_MODULE(b);
        exportModuleB();
    }

    ...
}