In the documentation of std::uniform_real_distribution
, the notation for initializing the uniform real random number generator is to use round brackets:
std::uniform_real_distribution rand01(0,1)
However, when I define this as a member of a class variable:
#include <iostream>
#include <random>
class randomnumber
{
public:
randomnumber()
{
std::random_device rd;
generator.seed(rd());
};
double get_rn()
{
return rand01(generator);
}
private :
std::mt19937 generator;
std::uniform_real_distribution<double> rand01(0.,1.);
};
int main(int argc,char *argv[])
{
randomnumber randnum;
for(int i=0;i<100;i++)
std::cout << randnum.get_rn() << std::endl;
}
The compiler fails with an error:
randtest.cpp:20:53: error: expected identifier before numeric constant
20 | std::uniform_real_distribution<double> rand01(0.,1.);
| ^~
randtest.cpp:20:53: error: expected ‘,’ or ‘...’ before numeric constant
randtest.cpp: In member function ‘double randomnumber::get_rn()’:
randtest.cpp:15:24: error: cannot convert ‘std::mt19937’ {aka ‘std::mersenne_twister_engine<long unsigned int, 32, 624, 397, 31, 2567483615, 11, 4294967295, 7, 2636928640, 15, 4022730752, 18, 1812433253>’} to ‘int’
15 | return rand01(generator);
| ^~~~~~~~~
| |
| std::mt19937 {aka std::mersenne_twister_engine<long unsigned int, 32, 624, 397, 31, 2567483615, 11, 4294967295, 7, 2636928640, 15, 4022730752, 18, 1812433253>}
randtest.cpp:20:53: note: initializing argument 1 of ‘std::uniform_real_distribution<double> randomnumber::rand01(int)’
20 | std::uniform_real_distribution<double> rand01(0.,1.);
The fix is to use curly brackets {}
instead of the round brackets ()
.
The question is, is this fix a fundamental fix? Meaning, can I trust the fixed code with {}
to always generate uniform random number between 0 and 1?
Also for the future purposes for similar cases, it would be greaet if someone can explain me why compiler behaves in this way.
I use for compiling g++
g++ -std=c++11 randtest.cpp
:
g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
is this fix a fundamental fix?
For this code, yes. But not in general.
can I trust the fixed code with {} to always generate uniform random number between 0 and 1?
Yes, std::uniform_real_distribution<double> rand01{0.,1.};
defines a uniform distribution with parameters of 0
and 1
, by calling the exact same constructor that std::uniform_real_distribution rand01(0,1)
does for non-class scopes.
But the way that the compiler searches for constructors is different when braces are used. Particularly for classes intended to work as collections (e.g. std::vector
), braces may choose a different constructor. A strong sign of this happening is when the class has a constructor (or multiple) for some std::initializer_list<...>
.
std::uniform_real_distribution::uniform_real_distribution()
doesn't have special handling for initializer lists which is what makes your specific example safe.