C++ - 模板化均匀分布?

C++ - Templated Uniform Distribution?

目前我正在重载这个函数来生成一个随机数:

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

可以用模板来做吗?我不知道如何为分发设置模板。

我们可以将 GetRand 的两个重载统一为一个函数模板。

首先请注意,如果T不是floatdoublelong double之一,则std::uniform_real_distribution<T>的效果是不确定的。 例如,C++ 标准草案 n4687 中的 29.6.1.1 一般要求 [rand.req.genl] 指出:

Throughout this subclause 29.6, the effect of instantiating a template:

...

d) that has a template type parameter named RealType is undefined unless the corresponding template argument is cv-unqualified and is one of float, double, or long double.

此外,29.6.8.2.2Class模板uniform_real_distribution[rand.dist.uni.real] 使用模板类型参数 RealType 描述 std::uniform_real_distribution,因此 std::uniform_real_distribution<int> 未定义:

template<class RealType = double>
class uniform_real_distribution {
    ...
};

此外,std::uniform_int_distribution<T> 也存在类似的限制。 因此,我们需要根据 T.

std::uniform_real_distribution<T>std::uniform_int_distribution<T> 之间切换分布类型

我们可以使用 std::is_floating_pointstd::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);
}

最后调用方如下:

DEMO

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)