How to std::bind() to create a data member? - c++

I'm generating random values with C++11 nice new generators and distributions. In a function it works like a charm and looks like this:
void foo() {
mt19937 generator;
uniform_int_distribution<unsigned> distribution;
auto dice = bind(distribution, generator);
// dice() will now give a random unsigned value
}
But how can I put all three objects in a class as data members? I can simply write generator and distribution as data members, but how do I make dice a data member without knowing (or wanting to know) its exact type? Suprisingly this
class X {
mt19937 generator;
uniform_int_distribution<unsigned> distribution;
decltype(bind(distribution, generator)) dice;
};
yields the error error C2660: 'bind' : function does not take 2 arguments in Visual Studio 2013.

You could always gasp write a function instead of using a lambda/bind/etc.:
class X {
mt19937 generator;
uniform_int_distribution<unsigned> distribution;
public:
auto dice() -> decltype(distribution(generator)) {
return distribution(generator);
}
// or alternatively
auto operator() () -> decltype(distribution(generator)) {
return distribution(generator);
}
};
Bonus points for parameterizing on the type of the generator and/or distribution, and for holding the generator with a std::shared_ptr so that you can make several objects with differing distributions that share the same engine. You'll eventually want a constructor to seed the generator as well - Ideally with something like std::random_device{}().
Or, the answer I think you are looking for:
class X {
mt19937 generator{std::random_device{}()};
uniform_int_distribution<unsigned> distribution{1,6};
public:
decltype(bind(std::ref(distribution), std::ref(generator))) dice{
bind(std::ref(distribution), std::ref(generator))
};
};
I'm sorry I mocked you for trying to use bind in the first place: it's actually kind of neat that you can write this class with "no code" in C++11. We need to get type-inference for class member declarations in C++17 so this could be:
class X {
auto generator = mt19937{std::random_device{}()};
auto distribution = uniform_int_distribution<unsigned>{1,6};
public:
auto dice = bind(std::ref(distribution), std::ref(generator));
};
Given that the latest Concepts Lite paper proposes using concept names anywhere in the language where auto can appear to mean "infer type, ill-formed if type doesn't model named concept," auto member declarations may not be out of the question.

It works on GCC. I’m pretty sure that’s just a compiler bug. Unfortunately this means that you have to bite the bitter pill and use one of the workarounds described in the other answers.

The result of std::bind is unspecified: this means that you cannot store its raw result without type inference. However, you can use std::function to encapsulate the result of bind:
#include <functional>
std::function<unsigned()> dice(std::bind(distribution, generator));
auto result = dice();
EDIT: As whoever said above, this is most clearly a Visual Studio issue. I can confirm that this compiles with VS2013:
#include <functional>
#include <random>
using namespace std;
class X {
mt19937 generator;
uniform_int_distribution<unsigned> distribution;
std::function<unsigned()> dice;
public:
X() : dice(bind(distribution, generator)) {}
unsigned roll() { return dice(); }
};
but changing the type of dice to decltype(bind(distribution, generator)) makes the whole thing fail with flying colors (even though it still works with clang).

Related

Proper design of RNG helper in C++

In my project, I want to have some kind of helper functions/class to work with random number generator. Main topic of the project is Monte Carlo simulations so I will be using it very often and in many places. Hence, I'm looking for ideas of designing such wrapper on C++ random library so I can randomize e.g. probability by calling simple function generateProbability(). I've came with 2 ideas, one is just class with needed functions. This solution looks nice, however I would have to create separate RNG objects inside every file/place what it's needed. The other solution is just creating separate namespace with global variables of pseudo-random engine, distributions and helper functions. I've prepared example code for both cases:
#pragma once
#include <random>
namespace rng {
std::mt19937_64 rng_engine(std::random_device{}());
std::uniform_int_distribution<uint8_t> zeroToNineDistrib(0, 9);
inline auto generateNumber() { return zeroToNineDistrib(rng_engine); }
} // namespace rng
class RNG {
public:
RNG() : rng_engine(std::random_device{}()), zeroToNineDistrib(0, 9){};
~RNG() = default;
auto generateNumber() { return zeroToNineDistrib(rng_engine); }
private:
std::mt19937_64 rng_engine;
std::uniform_int_distribution<uint8_t> zeroToNineDistrib;
};
What do you think about these solutions? Which one is 'better' in a way that it's more professional and considered as 'cleaner'? Or maybe you have other ideas on how to do that better?
I encourage you to discussion because I can see both pros and cons of either solution and can't decide which one should I pick.

Incorrectly seeding Mersenne Twister via constructor

What is wrong with my constructor? Every time I call a function (about once every five seconds) that is supposed to generate random numbers, it generates the same numbers. Each call instantiates one of these objects below. I thought I was seeding m_gen randomly with the output of m_rd's operator() call.
Could I pass in the result of m_rd() to the constructor? What would the signature be? Shuffler(std::random device& rd)? But then that would be more difficult for the user.
Edit:
Actually, if it's possible, I would prefer a solution where you don't need to pass anything into the constructor.
shuffler.h
#include <random>
class Shuffler
{
private:
std::random_device m_rd;
std::mt19937 m_gen;
public:
//! The default constructor.
Shuffler();
};
shuffler.cpp
#include "shuffler.h"
Shuffler::Shuffler() : m_gen(m_rd())
{
}
std::random_device is usually fine for this sort of thing, but it may not be on every platform. While most platforms' standard libraries implement it in terms of some underlying OS random functionality (i.e. /dev/urandom on Linux or CryptGenRandom on Windows), it is not required to do so by the C++ standard. On some platforms, high-quality random generators simply may not be available, and the standard allows std::random_device to be a simple, statically seeded PRNG. If it is, every std::random_device object will generate the same sequence of numbers.
For those reasons, you may want to go back to simple time-seeding. The standard
provides std::chrono::high_resolution_clock:
class Shuffler
{
private:
std::mt19937 m_gen;
public:
Shuffler()
: m_gen{static_cast<std::uint32_t>(
std::chrono::high_resolution_clock::now().time_since_epoch().count()
)}
{}
};
std::chrono::high_resolution_clock usually has a resolution of nanoseconds or hundreds of nanoseconds. This is high enough that two PRNGs seeded by calls to the high_resolution_clock are very unlikely to end up using the same seed. This is also not guaranteed though. For example, std::chrono::high_resolution_clock only has microsecond resolution on macOS, which may or may not be good enough for your purposes.
In the end, neither method is perfect. You may want to combine the two using std::seed_seq:
std::seed_seq make_seeds() {
thread_local std::random_device rd;
return {{
static_cast<std::uint32_t>(std::chrono::high_resolution_clock::now().time_since_epoch().count()),
rd()
}};
}
// Cast away rvalue-ness because the standard random generators need
// an lvalue reference to their seed_seq for some strange reason
template <typename T>
T& identity(T&& t) { return t; }
class Shuffler
{
private:
std::mt19937 m_gen;
public:
Shuffler()
: m_gen{identity(make_seeds())}
{}
};
As you can see, this is getting far from simple, and it's still not perfect. See these blog posts for more information about seeding and random number generators then you ever thought you wanted.
As in this example, you have to seed it and random_device doesn't seem to do the trick*:
// do this once somewhere
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
class Shuffler
{
private:
std::mt19937 m_gen;
public:
Shuffler() : m_gen(seed) {}
};
*As stated here, random_device is not a Seed Sequence!

using bind vs using pointers with random number generators

I had the following implementation in my code:
// first solution
//random.h
class Random{
public:
std::mt19937* gen;
std::uniform_real_distribution<double>* dis;
}
//random.cpp
Random::Random()
{
std::mt19937_64::result_type seed = chrono::high_resolution_clock::now().time_since_epoch().count();
gen = new std::mt19937(seed);
dis = new std::uniform_real_distribution<double>(0.0,1.0);
}
double Random::next()
{
double rand = 0;
rand_int = (*dis)(*gen);
return rand;
}
On the other hand someone else in the company did a different implementation, where he used the bind feature from c++11 as follows:
// second solution
//random.h
class Random{
public:
std::function<double()> real_rand;
}
//random.cpp
Random::Random()
{
std::mt19937_64::result_type seed = chrono::high_resolution_clock::now().time_since_epoch().count();
real_rand = std::bind(std::uniform_real_distribution<double>(0.0,1.0), mt19937_64(seed))
}
double Random::next()
{
double rand = 0;
rand = real_rand();
return rand;
}
Taking into account that you are supposed to have only one PRNG object, and you are supposed to seed it once, then you call that object every time you need a new random number, as the seed is used to create a series of random numbers in the PRNG. I can clearly see this being the case for the first solution.
The question is, how is bind() working behind the scenes? Is it creating a new object on every call? Is it really calling the (constructor) or the function()? How can it tell which one to call? Are there any differences between the solutions?
std::bind generates a function object which encapsulates the arguments provided to it. In effect your colleague's code generates the following object:
struct random_call
{
random_call(unsigned seed)
: _mt19937_64(seed)
, _uniform_real(0.0, 1.0)
{}
double operator() {
return _uniform_real(_mt19937_64);
}
std::mt19937_64 _mt19937_64;
std::uniform_real_distribution<double> _uniform_real;
};
so it looks ok (and actually pretty clever) to me!
One caveat is that you probably wouldn't want to make any copies of the binder object - even if it turns out to be copyable, copying it and then calling operator() on the original and the copy will yield the same numbers.

Factory class driven by a map for determining the object type

I'm having a brain freeze and can't figure out how to best solve this issue. I'm creating objects from my factory class by calling
CreateEnvironment<T>(ARGS);
Now lets say that i want to save alot of class-types into a map and iterate through the map and call the method at runtime like this:
ITERATION:
CrateEnvironment<(*it)>(world);
(*it) should be the class type, which could be FOO or BAR for example. How do i achieve this instead of having alot of if statements?
Best regards
For each class you could have a function that would serve as generator and create a new object and return a pointer to it (or better, a shared_ptr).
In your container you could then store a the generator function pointers.
Step by step explanations:
Suppose you have these classes to populate your world:
struct GO { virtual void say_hello()=0; }; // Game Object
struct A:GO { void say_hello() { cout<<"I'm a werewolf\n";} };
struct B:GO { void say_hello() { cout<<"I'm a soldier\n";}};
You can then define a generic GO generator:
template <class T>
shared_ptr<GO> generator() {
return make_shared<T>();
};
This would serve as subsititue for your "type" container (for the simplicity of the example I've used a vector, but you could easily opt for a map):
typedef shared_ptr<GO> (*gen_fn)();
vector <gen_fn> generators{generator<A>, generator<B>};
You could then populate your universe like this, without any if:
vector<shared_ptr<GO>> universe;
default_random_engine generator;
uniform_int_distribution<int> distribution(0,generators.size()-1);
for (int i=0; i<10; i++) {
int mytype = distribution(generator);
universe.push_back(generators[mytype]());
}
for (auto x: universe)
x->say_hello();
And here an online demo.
Statistical remark: As the distribution is uniform, you will have a high probability of having the roughly the same proportion of each type of object. If you'd like to have different distribution, you could add several times generators of the same type. For example, with generators{generator<A>, generator<B>, generator<B>}; you'd have around 66% of soldiers and 33% of werewolves.

c++ class members and delayed initialization [duplicate]

This question already has an answer here:
c++ calling non-default constructor as member [duplicate]
(1 answer)
Closed 9 years ago.
I am currently looking into new c++11 random library. For simplification, I created following class
class my_rand {
private:
std::mt19937_64 eng;
public:
my_rand() {
std::array<int, std::mt19937::state_size> seed_data;
std::random_device rd;
std::generate_n(seed_data.data(), seed_data.size(), std::ref(rd));
std::seed_seq seq(std::begin(seed_data), std::end(seed_data));
this->eng.seed(seq);
};
unsigned long long operator() () {
return this->eng();
};
};
so that I can just do my_rand rand; once and then repeatedly call rand() to generate random numbers.
However, now I want to use std::uniform_int_distribution to set bound to numbers I get. It seams obvious to specify bounds while creating the object, so that invocations stay the same. The problem is, if I add private member (something like std::uniform_int_distribution<long long> uid;) then later in constructor I will not be able to set bounds because uid will already be initialized. I could not find method of std::uniform_int_distribution which allowed to set limits after it is created.
I may well be missing some point here, so thanks in advance for any help.
Use initializer lists to construct member variables or base classes. (See here for more info)
my_rand(...arguments...) : uid(...arguments...) //<-- Initializer list
{
//...stuff...
} //<-- No semicolon after function definition.
If that doesn't suit your needs, you can always go like this:
myVar = int(27);
For example:
//Initial construction:
std::uniform_int_distribution<> testA(1, 6);
//Re-assignment by copy-construction (move-construction actually)
//and a temporary object.
testA = std::uniform_int_distribution<>(5, 10);