Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 653
cxxl Avatar asked Jan 08 '14 16:01

cxxl


1 Answers

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.

like image 118
Casey Avatar answered Sep 25 '22 14:09

Casey