C ++ - Шаблонное равномерное распределение? - PullRequest
1 голос
/ 21 марта 2019

В настоящее время я перегружаю эту функцию для генерации случайного числа:

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 Ответ

4 голосов
/ 21 марта 2019

Мы можем объединить обе перегрузки GetRand как шаблон функции.

Прежде всего, обратите внимание, что эффект std::uniform_real_distribution<T> не определенесли T не является одним из float, double и long double.Например, 29.6.1.1 Общие требования [rand.req.genl] в стандартном черновике C ++ n4687 гласит:

На протяжении всего этого подпункта 29,6 , эффектсоздания шаблона:

...

d) с параметром типа шаблона с именем RealType не определен, если только соответствующий аргумент шаблона не cv-unqualified и не равен единице float , double или long double .

Кроме того, 29,6 .8.2.2 Шаблон классаiform_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 и 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);
}

Наконец, сторона вызывающего абонента будетследующим образом:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...