In MSVS 2019 I used to declare my distribution const
. Yet in the latest MSVS2022 preview, I get an error:
error C3848: expression having type 'const std::uniform_real_distribution<double>' would lose some const-volatile qualifiers in order to call 'double std::uniform_real<_Ty>::operator ()<std::mt19937>(_Engine &)'
1> with
1> [
1> _Ty=double,
1> _Engine=std::mt19937
1> ]
If I strip the const
all is fine again. Is this a MSVS2022 quirk? Or was 2019 wrong all that time?
(example from https://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution)
#include <random>
#include <iostream>
int main()
{
std::random_device rd; // Will be used to obtain a seed for the random number engine
std::mt19937 gen(rd()); // Standard mersenne_twister_engine seeded with rd()
const std::uniform_real_distribution<> dis(1.0, 2.0); // this const will break in MSVS2022
for (int n = 0; n < 10; n) {
// Use dis to transform the random unsigned int generated by gen into a
// double in [1, 2). Each call to dis(gen) generates a new random double
std::cout << dis(gen) << ' ';
}
std::cout << '\n';
}
CodePudding user response:
const std::uniform_real_distribution<>
was never guaranteed to be usable. The standard did not specify that operator()
of std::uniform_real_distribution
is const
. In particular <random>
's distributions are allowed to have internal state, e.g. to remember unused bits returned from the generator or to store state if the transformation algorithm requires it.
However, standard library implementations are allowed to add const
on a non-virtual member function if that wouldn't affect any call to the function that would be well-formed without it according to the standard's specification. Therefore Microsoft's implementation was not non-conforming in allowing you to use the const
version, even if that is not guaranteed to work according to the standard.
Nonetheless Microsoft's standard library developers decided to remove the const
by-default anyway, to encourage portability with other standard library implementations. They left the option to define _ALLOW_RANDOM_DISTRIBUTION_CONST_OPERATOR
(e.g. on the command line /D_ALLOW_RANDOM_DISTRIBUTION_CONST_OPERATOR
) to get back the old non-portable behavior if someone really needs it.
All of this is explained and discussed in the corresponding issue https://github.com/microsoft/STL/issues/1912 and the pull request https://github.com/microsoft/STL/pull/2732.