将mt19937与random_device一起用作静态类成员时出错

时间:2015-08-18 11:54:42

标签: c++ c++11 random

我有一个名为 RandomNumberGenerator 的类,我想用 mt19937算法生成一个随机数。

我正在创建一个 random_device 的对象作为种子。

编译时,我收到的错误是: "No member named generate in std::__1::random_device".
我无法理解错误。也许我在初始化 random_device mt19937 的对象的方式上做错了,但我无法弄清楚错误是什么。
感谢一些帮助..

RandomNumberGenerator.h

class RandomNumberGenerator
{
    static std::random_device   m_rd;
    static std::mt19937         m_rng;
public:
    static double getRandomNumber(const double& rangeStart, const double& rangeEnd);
};

RandomNumberGenerator.cpp

#include "RandomNumberGenerator.h"

std::random_device   RandomNumberGenerator::m_rd;
std::mt19937         RandomNumberGenerator::m_rng(RandomNumberGenerator::m_rd);

double RandomNumberGenerator::getRandomNumber(const double& rangeStart, const double& rangeEnd)
{
    std::uniform_real_distribution<> randomizer(rangeStart, rangeEnd);
    return randomizer(m_rng);
}

1 个答案:

答案 0 :(得分:4)

啊,你只错过了一件小物品。

std::mt19937 RandomNumberGenerator::m_rng(RandomNumberGenerator::m_rd);

以上行是发送实例而不是种子。因此,它必须具有generate函数来提供它没有的种子。只需更改该行即可调用仿函数,一切顺利。

std::mt19937 RandomNumberGenerator::m_rng(RandomNumberGenerator::m_rd());

注意:

另外需要注意的一项是,您要在每次通话时分配新的std::uniform_real_distribution。虽然分布对象的重量很轻,但只要rangeStartrangeEnd对后续调用保持不变,请考虑将其设置为静态。但是,如果您做出决定,初始化范围值将是一个更艰难的决定。

如果您的程序在整个生命周期内都没有使用此类,请考虑将其作为实例类,并在ctor上取范围,以便在生成数字后进行完全清理。

希望这有帮助。

修改

如果你肯定希望它是静态的,另一种选择是分配并完全清理函数中的所有对象,这些对象将填充所有需要的值,类似于以下内容:

template<typename T, typename DISTRIBUTION>
static void fill(T* buffer, uint32_t const count, T const min, T const max)
{
    ASSERT(buffer);
    ASSERT(count);
    ASSERT(max > min);

    std::random_device randomDevice;
    std::mt19937_64 twisterEngine { randomDevice() };
    DISTRIBUTION<T> distribution(min, max);
    for (uint32_t bufferLocation = 0; bufferLocation < count; ++bufferLocation)
        buffer[bufferLocation] = distribution(twisterEngine);
}

然后将其用于以下各种类型:

uint32_t const COUNT = 31u;
double realValues[COUNT];
uint32_t intValues[COUNT];

RandomNumberGenerator::fill<double, std::uniform_real_distribution<double>>(&realValues[0], COUNT, 100.0, 200.0);
RandomNumberGenerator::fill<uint32_t, std::uniform_int_distribution<uint32_t>>(intValues, COUNT, 100u, 200u);

如果这看起来像一个丑陋的界面,那么将fill设为私有,并提供干净的公共方法,以提供您希望支持的几种类型。