Home > Enterprise >  std::generate_n cannot generate my objects
std::generate_n cannot generate my objects

Time:10-24

I have a very simple class, which has an x, y and z values. Like so:

class Individual
{
public:
    static std::unique_ptr<Individual> Spawn(std::mt19937& rng);
    Individual(double x, double y)
        :
        x(x),
        y(y)
    {
        SetZ();
    }
    double GetZ() const
    {
        return z;
    }
    
private:
    void SetZ()
    {
        z = x * 0.123f   y * 0.912f;
    }
private:
    double x = 0.0f;
    double y = 0.0f;
    double z = 0.0f;
};

The Spawn method just generates random values for x and y and spawns an individual:

std::unique_ptr<Individual> Individual::Spawn(std::mt19937& rng)
{
    std::uniform_real_distribution<double> dist(-10.0f, 10.0f);


    return std::make_unique<Individual>(dist(rng), dist(rng));
}

The problem is that in main.cpp I've got a vector of these individuals, and I'm trying to populate it with 10 random individuals via std::generate_n :

std::mt19937 rng = std::mt19937(std::random_device{}());

std::vector<std::unique_ptr<Individual>> individuals;
std::generate_n(individuals.begin(), 10,
    Individual::Spawn(rng));

However I'm getting an error: error C2064: term does not evaluate to a function taking 0 arguments.

What gives? What am i doing wrong? Any help/criticism is appreciated

CodePudding user response:

generate_n's last argument is meant to be a function, not a value. That function will be called n times, once for each element to generate. You are giving it a std::unique_ptr. Wrap your Spawn(rng) call in a lambda expression instead.

Additionally, std::generate_n requires an iterator to the start of a range that is at least n elements in size. It does not (it can't) use that iterator to insert new elements, non-member algorithms can never do that with an iterator. One solution is to wrap the container with std::back_inserter to create an output iterator that will extend the container as needed. Alternatively, you can resize the vector to a size of 10 before calling generate_n.

Acorrect implementation for your function is :

std::mt19937 rng = std::mt19937(std::random_device{}());

std::vector<std::unique_ptr<Individual>> individuals;
std::generate_n(
    std::back_inserter(individuals),
    10,
    [&rng](){ return Individual::Spawn(rng); });

Live demo : https://godbolt.org/z/756Ejscvd

  • Related