Home > Net >  Initializing distributions for use across class methods (C )
Initializing distributions for use across class methods (C )

Time:07-27

I am trying to make a class that has a set of rng distributions as class attributes, with class methods having access to these distributions. Trying to follow the example in the documentation, I've distilled the problem to the following mwe. The code returns the errors member "A::rd" is not a type name and no instance of overloaded function "std::uniform_real_distribution<_RealType>::operator() [with _RealType=double]" matches the argument list.

#include <random>
#include <iostream>
using namespace std;

class A{
private:
    // Declaration of variables...
 
    // Declare random number generators and distributions    
    random_device rd;
    mt19937 gen(rd());
    uniform_real_distribution<> zero_five_real_dist{0,5};

public:
    A(){
        // Initialization of variables...

        // Use distribution, here to print numbers
        for (int i; i<6; i  ) cout << zero_five_real_dist(gen) << " ";
        cout << endl;
    }

    void print_nums(){
        for (int i; i<6; i  ) cout << zero_five_real_dist(gen) << " ";
        cout << endl;
    }
};

int main(){
    A a_obj;
    a_obj.print_nums();

    return 0;
}

I've found two possible work-arounds, but I'm not sure if they're any good. The first is to just skip the use of the Mersenne twister engine,

class A{
private:
    mt19937 gen;
    uniform_real_distribution<> zero_five_real_dist{0,5};

public:
    A(){
        for (int i; i<6; i  ) cout << zero_five_real_dist(gen) << " ";
        cout << endl;
    }

    void print_nums(){
        for (int i; i<6; i  ) cout << zero_five_real_dist(gen) << " ";
        cout << endl;
    }
};

and the other one is to seed the rng engine in every function call.

class A{
private:
    random_device rd;
    uniform_real_distribution<> zero_five_real_dist{0,5};

public:
    A(){
        mt19937 gen(rd());
        for (int i; i<6; i  ) cout << zero_five_real_dist(gen) << " ";
        cout << endl;
    }

    void print_nums(){
        mt19937 gen(rd());
        for (int i; i<6; i  ) cout << zero_five_real_dist(gen) << " ";
        cout << endl;
    }
};

I'd greatly appreciate any input on how to make a good working implementation.

CodePudding user response:

Initialize the generator in the constructor initializer list instead.

A() : gen(rd()) {
   // ...
}

CodePudding user response:

The code line:

    mt19937 gen(rd());

is ambiguous. I get that error message with GNU C v11.3:

q73126760.cpp:14:17: error: 'rd' is not a type
   14 |     mt19937 gen(rd());
      |                 ^~
q73126760.cpp: In constructor 'A::A()':
q73126760.cpp:22:59: error: invalid use of non-static member function 'std::mt19937 A::gen(int (*)())'
   22 |         for (int i; i<6; i  ) cout << zero_five_real_dist(gen) << " ";
      |                                                           ^~~

Trouble is, one of the possible interpretations is that gen could be a member function of class A, returning some mt19937 object. Your code is a new victim of the parsing rule known under the sulfurous name of C Most Vexing Parse: the interpretation as a function declaration takes priority.

And as rd is not a proper type, the interpretation as a function declaration ultimately fails, and the parser is unable to backtrack.

This can be fixed, for example, by forcing the compiler to take rd() as an initializer, using curly braces, like this:

    mt19937 gen{rd()};
  • Related