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

3

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

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

是否可以使用模板来实现这个功能?我不知道如何将分发过程模板化。

1个回答

9
我们可以将两个重载的GetRand作为函数模板统一起来。
首先请注意,如果T不是floatdoublelong double中的一个,则std::uniform_real_distribution<T>的效果是未定义的。例如,在C++标准草案n4687的29.6.1.1通用要求[rand.req.genl]中指出:

在整个子句29.6中,实例化模板的效果:

...

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

此外,29.6.8.2.2类模板uniform_real_distribution [rand.dist.uni.real]描述了带有模板类型参数RealTypestd::uniform_real_distribution,因此std::uniform_real_distribution<int>是未定义的:
template<class RealType = double>
class uniform_real_distribution {
    ...
};
此外,std::uniform_int_distribution<T>也存在类似的限制。 因此,我们需要根据Tstd::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的递归构造,并应用该帖子中接受的答案,使函数变得线程安全。

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)

1
这正是我正在寻找的。非常感谢! - Alex Wicks
1
真是个巧妙的技巧。谢谢! - Patrick Pan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接