Reputation: 3207
In running the code below, the first half of arr
equals the last half. Why? I even tried various seeds, e.g. std::chrono::system_clock::now().time_since_epoch().count()
. Thanks.
#include <algorithm>
#include <iostream>
#include <random>
template<typename DistributionType>
class Rng
{
public:
template<typename ...Args>
Rng(Args&&... args) : dist(args...) { }
typename DistributionType::result_type operator()()
{
return dist(gen);
}
private:
std::default_random_engine gen;
DistributionType dist;
};
class UniformRealRng : public Rng<std::uniform_real_distribution<double>>
{
public:
UniformRealRng(const double a, const double b) : Rng(a, b) { }
};
int main()
{
constexpr int sz = 6;
constexpr int k = sz / 2;
double arr[sz];
UniformRealRng rng(0.0, 1.0);
std::generate(arr, arr + k, rng);
std::generate(arr + k, arr + sz, rng);
for (int i = 0; i < sz; ++i)
{
std::cout << arr[i];
}
std::cout << "\n";
}
Upvotes: 2
Views: 117
Reputation: 16242
Your answer is factually correct but it doesn't solve the problem. It only produces a compilation error when mistakenly(?) one tries to copy the random number generator.
It turns out that the code can be made to be semantically correct by using the std::reference_wrapper
library features.
std::generate(arr, arr + k, std::ref(rng));
std::generate(arr + k, arr + sz, std::ref(rng));
In this way you are basically forcing to pass the argument by reference.
Luckily the reference wrapper overloads the operator()
and therefore can be used for the generator without any additional code.
Complete code:
#include <algorithm>
#include <iostream>
#include <random>
#include <functional> //ref
template<typename DistributionType>
class Rng
{
public:
template<typename ...Args>
Rng(Args&&... args) : dist(args...) { }
// Rng(Rng&) = delete; // this is not needed for it to work
// Rng& operator=(Rng&) = delete; // you MAY want to copy the generator
typename DistributionType::result_type operator()()
{
return dist(gen);
}
private:
std::default_random_engine gen;
DistributionType dist;
};
class UniformRealRng : public Rng<std::uniform_real_distribution<double>>
{
public:
UniformRealRng(const double a, const double b) : Rng(a, b) { }
};
int main()
{
constexpr int sz = 6;
constexpr int k = sz / 2;
double arr[sz];
UniformRealRng rng(0.0, 1.0);
std::generate(arr, arr + k, std::ref(rng));
std::generate(arr + k, arr + sz, std::ref(rng));
for (int i = 0; i < sz; ++i)
{
std::cout << arr[i];
}
std::cout << "\n";
}
Upvotes: 0
Reputation: 3207
std::generate
takes its third argument by value, so rng
was being copied.
For safety, one could delete copying:
Rng(Rng&) = delete;
Rng& operator=(Rng&) = delete;
Upvotes: 3