const成员函数中的继承和随机数生成

Inheritance and random number generation in const member function

我有以下class继承结构

#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;
};

在 D2 的 random_correction 定义中,出现以下错误:“在此处请求的函数模板特化 '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> >' 实例化中”。 如果我在所有声明中删除 const 限定符,错误就会消失。 为什么?成员函数中的 const 限定符是否意味着 class 的任何成员都不会被修改?

作为解决方法,我想我可以用这种方式修改 class D2

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;
};

但是现在我收到错误:“没有匹配函数来调用 'const std::uniform_real_distribution<>' 类型的对象”。我想是因为生成一个随机数会改变 u 的状态(也可能是 rng 的状态)。这个对吗?会员有分配方便吗?

P.S。如果有任何设计错误或效率低下,请指出给我。

生成随机数不会改变 u 的状态。它的状态就是要生成的值的范围。

但它确实改变了 rng 的状态。 Pseudo-random 数字生成器通常是确定性的,这意味着 rng() 由当前状态决定,并且状态会在评估时发生变化,因此下次将生成不同的值。

要解决编译问题,您可以删除函数的 const 声明,也可以将 rng 声明为 mutable。它仍然会遇到某些问题,例如“并发访问 class 实例会导致数据竞争”。所以你可以考虑重新考虑设计。

RNG 引擎可以从 thread_local 关键字中获益...但是您需要以某种方式设计它,这样它就不会导致可能有点棘手的性能问题。

编辑:在使用 cppreference 签入后,显然 uniform_distribution 可以包含除分布范围之外的额外信息。可能是 RNG 引擎生成的一些数据,因此它可以将它们用于将来的调用,并且不需要经常使用引擎。