How do I pass a C++11 random number generator to a

2019-01-23 14:19发布

问题:

Do they all inherit from a base class? Do I have to use templates?

(I am referring to these http://www.codeguru.com/cpp/cpp/cpp_mfc/stl/article.php/c15319/)

I am doing this right now:

typedef std::mt19937 RNG;

and then

class Chooser {
public:
    Chooser(RNG& rng, uint n, uint min_choices, uint max_choices):

In other words, I'm passing references to RNG. How would I pass in an arbitrary generator?

Also, I realize this is maybe a different question, but how do I pass the generator to STL?

std::random_shuffle(choices_.begin(), choices_.end(), rng);

doesn't seem to work.


solution to passing generator:

typedef std::ranlux64_base_01 RNG;
typedef std::mt19937 RNGInt;

solution to passing to STL:

struct STL_RNG {
    STL_RNG(RNGInt& rng): gen(rng) {}       
    RNGInt& gen;
    int operator()(int n) { return std::uniform_int<int>(0, n)(gen); }
};

回答1:

They don't all inherit from a base (which is a little surprising), but it doesn't matter because that's not how C++ functors work.

For arbitrary RNGs of a single given type, you got it right as (now) posted.

If you mean, how do I define a function which accepts any random number generator as an argument.

template< class RNG > // RNG may be a functor object of any type
int random_even_number( RNG &gen ) {
    return (int) gen() * 2;
}

You don't need to use any more templates than this, because of type deduction.


Defining one function to accept different RNG's is trickier because semantically that requires having a common base type. You need to define a base type.

struct RNGbase {
    virtual int operator() = 0;
    virtual ~RGNBase() {};
};

template< class RNG >
struct SmartRNG : RNGBase {
    RNG gen;

    virtual int operator() {
        return gen();
    }
};

int random_even_number( RNGBase &gen ) { // no template
    return (int) gen() * 2; // virtual dispatch
}


回答2:

What worked for me was using an std::function:

#include <functional>
#include <random>

void exampleFunction(std::function<int()> rnd) {
    auto randomNumber = rnd();
}

std::minstd_rand rnd;
exampleFunction([&rnd](){ return rnd(); });

// This won't work as it passes a copy of the object, so you end up with the same
// sequence of numbers on every call.
exampleFunction(rnd);

You're not really passing around the random object, just a method to call the object's operator (), but it achieves the same effect.

Note that here the precision of the random number generator's return value may be reduced as the std::function is declared as returning an int, so you may want to use a different data type instead of int depending on your need for precision.



回答3:

Wrap it in a class or functor that fit your needs?



回答4:

I suggest two methods: Function Objects and Function Pointers. In either case, enable your class to receive a Function Object or a Function Pointer to the random number generator.

With a Function Object, you can define a base class, and have your receiving class implement functions that require a pointer to the base function object class. This gives you more freedom in defining many different function objects without changing the interface of the receiving class.



标签: c++ random c++11