在this answer on stackoverflow(答案#2)@remyabel推荐这个模板:
#include <random>
std::mt19937& prng_engine()
{
thread_local static std::random_device rd{};
thread_local static std::mt19937 engine{rd()};
// Or you can replace the two previous lines with:
//thread_local static std::mt19937
// prng{std::random_device{}()};
return engine;
}
template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
thread_local static std::uniform_int_distribution<T> dist{Min, Max};
return dist(prng_engine());
}
只有dist
只会创建一次,以便在线程中提供{T, Min, Max
}套件吗?
如果我使用(1, 10)
调用它,然后使用(11, 20)
调用它,是否会重新创建?
答案 0 :(得分:1)
因为它是静态的,所以dist只创建一次 - 第一次代码流过它。
第一次代码流过它时,Min和Max的值将是1和10.
在第二次调用时,不会重新创建dist,因此忽略Min和Max的新值,并获得1到10之间的随机数。
编辑:
这是getRandomNumberBetween的一个实现,可以满足您的需求:
template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
using range_t = std::pair<T, T>;
using map_t = std::map<range_t, std::uniform_int_distribution<T>>;
static thread_local map_t range_map;
auto i = range_map.find(range_t(Min, Max));
if (i == std::end(range_map))
{
i = range_map.emplace(std::make_pair(Min, Max), std::uniform_int_distribution<T> { Min, Max}).first;
}
return i->second(prng_engine());
}
答案 1 :(得分:1)
每个T
只会创建一次(函数模板的每个实例都有自己的本地静态变量副本)。您可以查看:
std::cout << getRandomNumberBetween(0, 1) << '\n'
<< getRandomNumberBetween(10, 20) << '\n'
<< "------------------------\n"
<< getRandomNumberBetween('a', 'b') << '\n'
<< getRandomNumberBetween('c', 'z') << '\n';
由于分发对象是轻量级的,因此您可以在需要随机数时简单地构建新分布(例如Vary range of uniform_int_distribution):
template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
std::uniform_int_distribution<T> dist{Min, Max};
return dist(prng_engine());
}
但您也可以考虑this implementation:
template<typename T>
T getRandomNumberBetween(T Min, T Max)
{
using distribution_type = std::uniform_int_distribution<T>;
using param_type = typename distribution_type::param_type;
thread_local std::uniform_int_distribution<T> dist;
return dist(prng_engine(), param_type(Min, Max));
}