对于整数类型,有std::uniform_int_distribution。您必须使用 if constexpr 或使用 SFNIAE(具有类型特征)分别处理浮点和积分。顺便提一句。 std::uniform_real_distribution 中有一条注释:如果 this 不是 float、double 或 long double 之一,则效果未定义。(“this”涉及模板类型。)
由 SFINAE 区分的两个独立函数:
#include <iostream>
#include <random>
template <typename T,
std::enable_if_t<std::is_integral_v<T>, int> = 0
>
T randm(T low, T high)
{
static std::random_device seeder;
static std::mt19937 gen(seeder());
std::uniform_int_distribution<T> dis(low, high);
return dis(gen);
}
template <typename T,
std::enable_if_t<std::is_floating_point_v<T>, int> = 0
>
T randm(T low, T high)
{
static std::random_device seeder;
static std::mt19937 gen(seeder());
std::uniform_real_distribution<T> dis(low, high);
return dis(gen);
}
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(std::cout << randm(0, 10) << std::endl);
DEBUG(std::cout << randm(0.0f, 10.0f) << std::endl);
}
输出:
std::cout << randm(0, 10) << std::endl;
4
std::cout << randm(0.0f, 10.0f) << std::endl;
9.05245
Live Demo on coliru
使用if constexpr(至少需要 C++17):
#include <iostream>
#include <random>
template <typename T>
T randm(T low, T high)
{
static std::random_device seeder;
static std::mt19937 gen(seeder());
if constexpr (std::is_integral_v<T>) {
std::uniform_int_distribution<T> dis(low, high);
return dis(gen);
}
if constexpr (std::is_floating_point_v<T>) {
std::uniform_real_distribution<T> dis(low, high);
return dis(gen);
}
return T(); // ERROR?
}
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(std::cout << randm(0, 10) << std::endl);
DEBUG(std::cout << randm(0.0f, 10.0f) << std::endl);
}
输出:
std::cout << randm(0, 10) << std::endl;
7
std::cout << randm(0.0f, 10.0f) << std::endl;
3.51174
Live Demo on coliru
灵感来自 Jarod42s comment 另一个 C++11 解决方案:
#include <iostream>
#include <random>
#include <type_traits>
template <typename T>
T randm(T low, T high)
{
static std::random_device seeder;
static std::mt19937 gen(seeder());
typename std::conditional<std::is_integral<T>::value,
std::uniform_int_distribution<T>,
std::uniform_real_distribution<T>
>::type dis(low, high);
return dis(gen);
}
#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\n"; __VA_ARGS__
int main()
{
DEBUG(std::cout << randm(0, 10) << std::endl);
DEBUG(std::cout << randm(0.0f, 10.0f) << std::endl);
}
输出:
std::cout << randm(0, 10) << std::endl;
2
std::cout << randm(0.0f, 10.0f) << std::endl;
4.36778
Live Demo on coliru
Jarod42 还指出了这种方法的另一个弱点:std::is_integral 涵盖了任何整数类型(包括 char 甚至 bool 的变体),但如果模板类型 是,std::uniform_int_distribution 实际上是未定义的不是 short、int、long、long long、unsigned short、unsigned int、unsigned long 或 unsigned long long 之一。
answer to templating a random number generator in c++ 提供了更好的替代方案。