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

Ale*_*cks 2 c++ templates overloading 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);                                                                                                                                                                          
}                                                                                                                                                                                             
Run Code Online (Sandbox Code Playgroud)

是否可以使用模板来做到这一点?我不知道如何模板分发。

Hir*_*oki 6

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

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

在本子条款29.6 中,实例化模板的效果:

...

d) 具有名为RealType的模板类型参数是未定义的,除非相应的模板参数是 cv-unqualified 并且是floatdoublelong double 之一

另外,29.6 .8.2.2 Class template 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 {
    ...
};
Run Code Online (Sandbox Code Playgroud)

此外,对于 存在类似的限制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;
Run Code Online (Sandbox Code Playgroud)

那么GetRand可以将的两个重载统一到下面的函数模板中。在这里,我也避免递归建设std::mt19937_64,使函数线程安全的应用接受的答案在这个职位

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);
}
Run Code Online (Sandbox Code Playgroud)

最后,调用方将如下所示:

演示

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)
Run Code Online (Sandbox Code Playgroud)