I have the following class inheritance structure
#include <random>
class ABC{
protected:
std::mt19937_64 rng;
double a();//calls random correction
virtual double random_correction() const=0;
public:
double x;
explicit ABC(const double x0) :
rng(std::random_device{}()), x(x0){}
ABC(const ABC& other)=default;
ABC& operator=(const ABC& other)=default;
ABC(ABC&& other) noexcept = default;
ABC& operator=(ABC&& other) noexcept = default ;
virtual ~ABC()=default;
virtual void update(const int step_number)=0;//calls a and uses rng
};
class D1 : public ABC{
private:
double y;
double random_correction() const override {return 0;};
public:
D1(const double x0, const double y0):
ABC(x0), y(y0){}
D1(const D1& other)=default;
D1& operator=(const D1& other)=default;
D1(D1&& other) noexcept = default;
D1& operator=(D1&& other) noexcept = default ;
~D1() override=default;
void update(const int step_number) override;
};
class D2 : public D1{
private:
double noise;
double random_correction() const override {
static std::uniform_real_distribution<> u{-noise, noise};
return u(rng); //error here
};
public:
D2(const double x0, const double y0, const double na):
D1(x0,y0), noise(na) {}
D2(const D2& other)=default;
D2& operator=(const D2& other)=default;
D2(D2&& other) noexcept = default;
D2& operator=(D2&& other) noexcept = default ;
~D2() override=default;
};
In the definition of random_correction of D2 I get the following error: "in instantiation of function template specialization 'std::uniform_real_distribution::operator()<const std::mersenne_twister_engine<unsigned long, 64, 312, 156, 31, 13043109905998158313, 29, 6148914691236517205, 17, 8202884508482404352, 37, 18444473444759240704, 43, 6364136223846793005> >' requested here" . If I erase the const qualifier in all the declaration the error disappear. Why? Doesn't a const qualifier in a member function mean that no member of the class is going to be modified?
As a workaround I thought I could modify the class D2 in this way
class D2 : public D1{
private:
double noise;
std::uniform_real_distribution<> u;
double random_correction() const override {
return u(rng); //error always here
};
public:
D2(const double x0, const double y0, const double na):
D1(x0,y0), noise(na) {u.param(std::uniform_real_distribution<>::param_type{-noise, noise});}
D2(const D2& other)=default;
D2& operator=(const D2& other)=default;
D2(D2&& other) noexcept = default;
D2& operator=(D2&& other) noexcept = default ;
~D2() override=default;
};
However now I get the error: "no matching function for call to object of type 'const std::uniform_real_distribution<>'". I suppose because generating a random number changes the state of u (and maybe of rng as well). Is this correct? Is it convenient to have a distribution as a member?
P.S. Please, if there is any design error or inefficiency point it out to me.
CodePudding user response:
Generating random number doesn't change the state of u
. It's state is just what range of values to be generated.
But it does change the state of rng
. Pseudo-random number generators are usually deterministic meaning that rng()
is determined by the current state and the state will change upon evaluation so next time a different value will be produced.
To fix the compilation issue, you can either drop the const declaration of the function or you can declare rng
to be mutable
. It will still bear certain problems like "accessing the class instance concurrently will cause data races". So you might consider rethinking the design.
RNG engines can benefit from thread_local
keyword... but you'll need to design it in a way so it won't cause performance issues which can be a bit tricky.