4

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?

Community
  • 1
  • 1
SilverbackNet
  • 2,076
  • 17
  • 29
  • `variate_generator` is not a part of C++0x, it's only in TR1 (just commenting on the tags) – Cubbi Oct 16 '10 at 05:09
  • this compiles just fine on my VS2010 box... if you're trying to save overhead initialize 'line' as well. – Rick Oct 16 '10 at 07:28

3 Answers3

6

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.

Output

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 *
Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • I wonder when that changed, because it wasn't in anything I found when I looked a couple of months ago. But that's a much handier and more useful method than using variate_generator<>. – SilverbackNet Dec 18 '10 at 06:08
3

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.

Cubbi
  • 46,567
  • 13
  • 103
  • 169
-1
mt19937 eng(GetTickCount());

You cannot initialize a global variable with a non-static expression.

Alexander Rafferty
  • 6,134
  • 4
  • 33
  • 55