I'm using VC 2010 and trying to keep the overhead and duplicated code of certain functions low, by placing the random definitions in the constructor of each class instance, then calling as necessary from there. What I have now, simplified, is:
#include <random>
#include <Windows.h>
mt19937 eng(GetTickCount());
class Cycles {
int line;
normal_distribution<> rand_norm;
variate_generator<mt19937&,normal_distribution<>> r_norm;
public:
Cycles()
: rand_norm(0.85,0.05),
r_norm(eng,rand_norm) {
line=0;
}
}
Unfortunately that doesn't work, and I end up with this error:
\vc\include\random(513): error C2248: 'std::tr1::_Ewrap<_Engine,_Tgt_type>::operator =' : cannot access private member declared in class 'std::tr1::_Ewrap<_Engine,_Tgt_type>'
\vc\include\random(446) : see declaration of 'std::tr1::_Ewrap<_Engine,_Tgt_type>::operator ='
This diagnostic occurred in the compiler generated function 'std::tr1::variate_generator<_Engine,_Distrib> &std::tr1::variate_generator<_Engine,_Distrib>::operator =(const std::tr1::variate_generator<_Engine,_Distrib> &)'
I understand that these should be initialized prior to the opening of the constructor, or else it errors because of the lack of a default constructor, but I don't understand why this fails. My C++ fu is quite rusty.
Every example I've seen shows the distributor and generator being initialized globally or locally in the function that calls it, which seems silly to me, as I have several member functions that will be using r_norm that are called in a tight loop. It fails the smell test badly. Doesn't anyone know what I'm missing?
bind()
is used in c++0x instead of variate_generator<>
:
#include <functional> // bind
#include <iostream>
#include <vector>
#include <random>
namespace {
std::random_device generate_seed;
std::mt19937 eng(generate_seed());
class Cycles {
int line;
std::normal_distribution<> rand_norm;
std::function<double()> r_norm;
public:
Cycles(): line(0), rand_norm(0.85, 0.05), r_norm(std::bind(rand_norm, eng))
{
// print distribution
std::vector<size_t> freq(200);
for (int i = 0; i < 900; ++i) ++freq.at(std::round(r_norm()*100));
size_t line = 0, max_line = freq.size()-1;
for ( ; not freq[line] and line <= max_line; ++line);
for ( ; not freq[max_line] and max_line >= line; --max_line);
for ( ; line <= max_line; ++line) {
std::cout << line << '\t';
for (size_t j = 0; j < freq[line]; ++j) std::cout << '*';
std::cout << std::endl;
}
}
};
}
int main() {
Cycles c;
}
The plot is inspired by C++0xFAQ.
72 **
73 ***
74 ******
75 ********
76 *****************
77 ********************
78 *******************************
79 ************************************************
80 *************************************************
81 **********************************************************
82 ************************************************************
83 ***********************************************************
84 ************************************************************************
85 ********************************************************************************
86 *********************************************************************
87 ************************************************************
88 ****************************************************
89 *************************************
90 **********************************
91 **************************************
92 *************************
93 ******************
94 ********************
95 ************
96 ****
97 **********
98 ***
99 **
100 **
101 *
don't have MSVC at hand, but with gcc, this will compile if you replace
variate_generator<mt19937&,normal_distribution<>> r_norm;
with
variate_generator<mt19937, normal_distribution<> > r_norm;
(note the lack of &
)
Incidentally, std::random_device
is probably a better source of randomness than GetTickCount()
, although I don't know how it's implemented in MSVC.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With