C ++ 11 std :: generate e std :: uniform_real_distribution chamados duas vezes dão resultados estranhos

Chamar o algoritmo std :: generate do STL duas vezes em contêineres diferentes produz resultados equivalentes.

Considere que eu quero preencher dois arrays float com números aleatórios entre -1. e 1. :

std::array<float, 1000> x;
std::array<float, 1000> y;

std::random_device rd;
std::mt19937_64 gen(rd());
std::uniform_real_distribution<float> dis(-1.f, 1.f);
auto rand = std::bind(dis, gen);
std::generate(x.begin(), x.end(), rand);
std::generate(y.begin(), y.end(), rand);

Você pode testá-lo aqui:http://ideone.com/X712IU. Ambas as matrizes são preenchidas com os mesmos valores exatos:

0:  -0.411968,  -0.411968
1:    0.55158,    0.55158
2:    0.69889,    0.69889
3:  -0.901328,  -0.901328
4:  -0.556142,  -0.556142
5:  -0.798431,  -0.798431
6:  -0.570874,  -0.570874
7:   0.928999,   0.928999
8:   0.118056,   0.118056
9:  -0.655123,  -0.655123

Agora, se eu fizer um novo gerador entre os gera funciona ok:

std::array<float, 1000> x;
std::array<float, 1000> y;

// Generators in different scopes, OK
std::random_device rd;
{
  std::mt19937_64 gen(rd());
  std::uniform_real_distribution<float> dis(-1.f, 1.f);
  auto rand = std::bind(dis, gen);
  std::generate(x.begin(), x.end(), rand);
}
{
  std::mt19937_64 gen(rd());
  std::uniform_real_distribution<float> dis(-1.f, 1.f);
  auto rand = std::bind(dis, gen);
  std::generate(y.begin(), y.end(), rand);
}

Dá:

0:   0.391496,   -0.64993
1:   0.429592,   0.835015
2: 0.00735116,    0.77657
3:  -0.548355, -0.0794801
4:  -0.312095,  -0.119841
5:   0.931296,   0.997449
6:  -0.934924,  -0.832223
7:   0.432267,   0.181224
8:   0.942709,   0.165024
9:   0.315852,  -0.654576

E agora com o mesmo gerador usando loops, ele também funciona:

// Both arrays assigned in the same loop, OK
for(size_t i = 0; i < x.size(); ++i)
{
  x[i] = rand();
  y[i] = rand();
}

// Arrays in separated loops, OK
for(size_t i = 0; i < x.size(); ++i)
  x[i] = rand();

for(size_t i = 0; i < y.size(); ++i)
  y[i] = rand();

Parece algo relacionado a std :: generate, mas não consigo descobrir o que causaria esse comportamento.

Alguma explicação? Felicidades

EDITAR:

Como apontado por dotcavader, o problema vem simplesmente porque o objeto gerador foi copiado (ambos por std :: bind e std :: generate). Portanto, o gerador começa com o mesmo estado interno exato para ambos os geradores.

Só para completar a resposta, Praetorian e Casey deram duas soluções fáceis para isso:

Usando std :: reference_wrapper para armazenar uma referência na ligação em vez de uma cópia:

auto rand = std::bind(dis, std::ref(gen));

Usando um lambda que retorna uma referência:

auto rand = [&](){ return dis(gen); };

questionAnswers(1)

yourAnswerToTheQuestion