5

The following code works fine

#include <iostream>
#include <random>

int main() {
    std::default_random_engine generator;
    std::normal_distribution<double> distribution(5.0, 2.0);
    std::vector<double> v(100);

    std::generate(v.begin(), v.end(), [&] () { return distribution(generator); });

    return 0;
}

However, changing the capture list of the lambda to [=] or [&, distribution] or [&, generator] causes

rand.cpp:9:59: error: no matching function for call to object of type 'const std::normal_distribution<double>'
error: assigning to 'double' from incompatible type 'void'

Are there some kinds of objects can not be captured by value in a lambda ?

Saddle Point
  • 3,074
  • 4
  • 23
  • 33

2 Answers2

6

Looks like std::normal_distribution<double>::operator() is not const. So you have to add mutable keyword to your lambda:

std::generate(v.begin(), v.end(), [=] () mutable { 
   return distribution(generator); 
});

std::generate(v.begin(), v.end(), [&, distribution] () mutable { 
   return distribution(generator); 
});

These both work fine.

WindyFields
  • 2,697
  • 1
  • 18
  • 21
6

In general, capture by values requires the object to be copyable. Both std::default_random_generator and std::normal_distribution are copyable, so this shouldn't be a problem here.

Lambda captures are always const values or const references. Random number generation is inherently stateful, so the called operator() cannot be const because it may modify the object state. The error message cryptically reports this by saying that there is no function to call on a const std::normal_distribution<double>.

If you want to modify the captured objects, you have to declare the lambda as mutable

#include <iostream>
#include <random>
#include <algorithm>

int main() {
    std::default_random_engine generator;
    std::normal_distribution<double> distribution(5.0, 2.0);
    std::vector<double> v(100);

    std::generate(v.begin(), v.end(), [generator, distribution] () mutable { return distribution(generator); });

    return 0;
}
Jens
  • 9,058
  • 2
  • 26
  • 43
  • Thanks for your explanation, the error message is just a bit hard to understand. Is it good practice to always use `&` for none built-in types ? – Saddle Point Aug 28 '17 at 07:07
  • @displayname - it depends, but yes, in this particular case you definitely don't want to work off a copy of the `generator`. – rustyx Aug 28 '17 at 07:20