Search code examples
c++boostrandomstdublas

std::generate - How do I use a random number generator?


In my programming I need to create a user-defined number of ublas vectors. I would like to do this with std::generate. However I get compiler errors that make it impossible for me.

The code I'm using:

for (size_t a_= 0; a_ < p_; a_++)
{
    ublas::vector<double> next_vhat(size_of_vec);
    std::generate(next_vhat.begin(), next_vhat.end(), mygen.give_rnd);
    v_hat_.push_back(next_vhat);
}

I had to create a class specifically for the function call, since std::generate won't allow me to use a function with an argument as the third argument ("gen", see here. I need the numbers to be normal distributed, so the function call to the distribution function must contain, as an argument, the random number generator. Since it didn't allow me to call it with the argument, I had to write a class to do this for me.

The class I have written:

class RandGen
{
public:
RandGen()
: generator()
, norm_dist(0.0,1.0)
, random_seed(static_cast<unsigned>(std::time(NULL)))
{}

double give_rnd() { return (double) norm_dist(generator); }

private:
base_gen_t generator;
boost::random::normal_distribution<double> norm_dist; //Standard normal    distribution
unsigned random_seed;
};

The error I'm getting

When trying to compile the whole thing, I get the following error:

 error: cannot convert ‘RandGen::give_rnd’ from type ‘double (RandGen::)()’ to type ‘double (RandGen::*)()’

I have no idea what the compiler wants me to do here, or why it has so much trouble with this at all. Any advice is very appreciated.


Solution

  • You need to pass a callable object. That is, either a function pointer (not a member function pointer, which is what mygen.give_rnd is) or an object of a class that overloads operator(). You can just change your function give_rnd to this:

    double operator()() { return (double) norm_dist(generator); }
    

    And then, just pass your object directly to std::generate

    std::generate(..., ..., mygen);
    

    If, for some reason, you wanted to keep your RandGen class as it is, you would need to wrap it in another functor or lambda:

    std::generate(..., ..., [&mygen]() { return mygen.give_rnd(); });