当前,我正在重载此函数以生成一个随机数:
float GetRand(float lower, float upper) {
std::random_device rd;
std::mt19937_64 mt(rd());
std::uniform_real_distribution<float> dist(lower,upper);
return dist(mt);
}
int GetRand(int lower, int upper) {
std::random_device rd;
std::mt19937_64 mt(rd());
std::uniform_int_distribution<int> dist(lower,upper);
return dist(mt);
}
是否可以使用模板执行此操作?我不知道如何为发行版做模板。
答案 0 :(得分:4)
我们可以将GetRand
的两个重载统一为函数模板。
首先,请注意,如果T
不是float
,double
和long double
之一,则std::uniform_real_distribution<T>
的作用是不确定的。
例如,C ++标准草案n4687中的 29.6.1.1一般要求[rand.req.genl] 指出:
在本条 29.6 中,实例化模板的效果:
...
除非对应的模板,否则未定义具有名为 RealType 的模板类型参数的d) 参数是cv不合格的,并且是 float , double 或 long double 之一。
此外, 29.6 .8.2.2类模板Uniform_real_distribution [rand.dist.uni.real] 描述了std::uniform_real_distribution
模板类型参数为 RealType
,因此std::uniform_real_distribution<int>
未定义:
template<class RealType = double> class uniform_real_distribution { ... };
此外,std::uniform_int_distribution<T>
也存在类似的限制。
因此,我们需要根据std::uniform_real_distribution<T>
在std::uniform_int_distribution<T>
和T
之间切换分布类型。
我们可以使用std::is_floating_point
和std::is_integral
来检查上述限制,并进行以下切换:
#include <random>
#include <type_traits>
template<class T>
using uniform_distribution =
typename std::conditional<
std::is_floating_point<T>::value,
std::uniform_real_distribution<T>,
typename std::conditional<
std::is_integral<T>::value,
std::uniform_int_distribution<T>,
void
>::type
>::type;
然后GetRand
的两个重载可以统一为以下功能模板。
在这里,我还避免了std::mt19937_64
的递归构造,并使函数安全使用this post中接受的答案。
template <class T>
T GetRand(T lower, T upper)
{
static thread_local std::mt19937_64 mt(std::random_device{}());
uniform_distribution<T> dist(lower,upper);
return dist(mt);
}
最后,主叫方如下:
auto i = GetRand<int> (0, 1); // 0 or 1
auto f = GetRand<float> (0, 1); // [0, 1)
auto d = GetRand<double>(0, 1); // [0, 1)