2

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

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

是否可以使用模板执行此操作?我不知道如何模板分发。

4

1 回答 1

7

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

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

在整个29.6小节中,实例化模板的效果:

...

d) 具有名为RealType的模板类型参数是未定义的,除非相应的模板参数是 cv-unqualified 并且是floatdoublelong 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我们可以使用and来检查上述限制,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并使函数线程安全地应用本文中接受的答案

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)
于 2019-03-21T07:40:16.330 回答