Search code examples
c++c++11randomstd-function

Passing uniform_int_distribution as parameter (with state)


I'm trying to write some code that will use random generators but allow you to seed it (for reproducability).

The code looks something like the following (trying to create a snippet that can be run)

#include <cstdio>                                      
#include <functional>
#include <random>

class CarterWegmanHash {
 private:
  unsigned int a_;
  unsigned int b_;

 public:
  // What should the signature of this be?
  CarterWegmanHash(int k, std::function<unsigned int()> unif_rand) {
    // Other stuff
    a_ = unif_rand();
    b_ = unif_rand();
  }
  unsigned int get_a() { return a_; }
  unsigned int get_b() { return b_; }
};

int main() {
  // Construct our uniform generator
  int n = 8;
  std::random_device rd;                                                        
  auto unif_rand = std::bind(                                                   
      // uniform rand from [0, n - 1]                                           
      std::uniform_int_distribution<unsigned int>(0, pow(2, n)),                
      std::mt19937(rd()));                                                      

  for (int i = 0; i < 5; ++i) {
    // How do I call this?
    CarterWegmanHash h_k(n, unif_rand);
    printf("seeds for h_%d are %u, %u\n", i, h_k.get_a(), h_k.get_b());
  }
}

I'd like each of the CarterWegmanHash objects to be able to have different seeds from unif_rand, but (not suprisingly), they're all the same.

Passing by pointer gives me error: no matching function for call to ‘CarterWegmanHash::CarterWegmanHash, and passing by ref gives me cannot bind non-const lvalue reference of type ‘std::function<unsigned int()>&’ to an rvalue of type ‘std::function<unsigned int()>’

Is there a way to pass a random number generator like uniform_int_distribution so the state is maintained?


Solution

  • You can just create your distribution and mt19937 in main and capture them in a lambda:

    std::uniform_int_distribution<unsigned int> distribution(0, pow(2, n));
    std::mt19937 mt(rd());
    auto unif_rand = [&](){ return distribution(mt); };
    

    Or with bind:

    auto unif_rand = std::bind(std::ref(distribution), std::ref(mt));