I have a C++ class which contains some kind of "static state" ("m_engine" in this particular case):
class RndGenerator
{
public:
static void setInitialSeed(unsigned int seed);
static unsigned int rndNumber();
...
private:
...
RndGenerator();
static std::mt19937 m_engine;
};
This class is used extensively in my project, on C++ level.
After exposing RndGenerator via Boost.Python:
class_<RndGenerator, boost::noncopyable>("RndGenerator", no_init)
.def("setInitialSeed", &RndGenerator::setInitialSeed)
.staticmethod("setInitialSeed")
.def("rndNumber", &RndGenerator::rndNumber)
.staticmethod("rndNumber")
;
I would like to have possibility to set initial seed from Python level:
RndGenerator.setInitialSeed(1234)
I would expect, that after this line all calls to RndGenerator::rndNumber(), on C++ level, would take into account just specified initial seed (1234). However this is not the case.
Is there any problem with classes containing static members exposed to Python? Or is my problem related to singleton-like nature of RndGenerator?
There should be no problems with Boost.Python using static data members or static member functions on C++ classes being exposed. Is it possible that this is a false-positive? Alternatively, for more complex and specific cases where the same template is instantiated in multiple translation units, then with dynamic libraries, multiple instances of static data members with the same symbolic name may reside within the same process space.
Regardless, here is a complete example demonstrating the expected behavior of static member functions and static data members on a class exposed with 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")
;
}
Interactive usage:
>>> 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))