Search code examples
c++c++11

Generate random numbers of type T


I am writing a program that holds a list<T> where T is either int or double. I want to make a function, using components from the header <random>, that generates numbers of type T. I can't find a distribution that takes T as template argument.

The function is then going to be used in a call to the generate function:

generate(myList.begin(), myList.end(), RandomGenerator())

How do I go about doing this?

I have tried to create a class called RandomGenerator and overload the operator() for it. When i try to pass an argument to the overloaded operator() i get an error.

Function call, Random(b) is a function object with int argument b:

generate(rList.begin(), rList.end(), Random(b)); 

Code for overloading (), where n is sort of a "dummy"-variable for just telling what type it is:

int operator()(int n)
{
    std::uniform_int_distribution<int> dist(1000, 2000);
    return dist(gen);
}

Error message:

Error   2   error C2440: '<function-style-cast>' : cannot convert from 'int' to 'Random'    

Error   3   error C2780: 'void std::generate(_FwdIt,_FwdIt,_Fn0)' : expects 3 arguments - 2 provided    

Solution

  • In addition to Joey's answer, the following should play nicely with std::generate. Disclaimer: I'm terrible at metaprogramming, please do point out any mistakes or possible improvements. This is a C++11 solution, with C++14 it would be a bit shorter.

    Live demo on Coliru.

    #include <algorithm>
    #include <iostream>
    #include <list>
    #include <random>
    #include <type_traits>
    
    template<typename T,
             typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
    class random_generator {
        using distribution_type = typename std::conditional<
                std::is_integral<T>::value,
                std::uniform_int_distribution<T>,
                std::uniform_real_distribution<T>
            >::type;
    
        std::default_random_engine engine;
        distribution_type distribution;
    
    public:
        auto operator()() -> decltype(distribution(engine)) {
            return distribution(engine);
        }
    };
    
    template<typename Container, typename T = typename Container::value_type>
    auto make_generator(Container const&) -> decltype(random_generator<T>()) {
        return random_generator<T>();
    }
    
    int main() {
        auto l = std::list<double>(10);
    
        std::generate(std::begin(l), std::end(l), make_generator(l));    
    
        for (auto i : l) {
            std::cout << i << " ";    
        }
    }