mercredi 24 octobre 2018

How to call the seed_seq constructor of a random generator from a member initialization list?

I have a class with a mersenne_twister_engine member that I want to initialize with a seed_seq constructed from a string. Initially I tried this:

class A
{
private:
    std::mt19937_64 rng;

public:
    A(std::string seed) : rng(std::seed_seq(seed.begin(), seed.end())) { }
};

But that doesn't compile, because:

(...) cannot convert argument 1 from 'std::seed_seq' to '_Seed_seq &'

I can get it to work like this:

class B
{
private:
    std::mt19937_64 rng;

public:
    B(std::string seed)
    {
        std::seed_seq seedSeq(seed.begin(), seed.end());
        rng = std::mt19937_64(seedSeq);
    }
};

But if I understand correctly, the member variable rng will now be constructed twice, so if possible, I'd like to avoid that. So, my main question is: Is it possible to make this work without initializing rng twice?

Before anyone suggests, I've also tried using a separate member function to construct the seed_seq object, but the only way I can get it to compile is by returning a const ref like this:

class C
{
private:
    std::mt19937_64 rng;

    const std::seed_seq& makeSeedSeq(std::string seed)
    {
        return std::seed_seq(seed.begin(), seed.end());
    }

public:
    C(std::string seed) : rng(makeSeedSeq(seed)) { }
};

Class C does compile, but when testing with different strings, the results are always the same and always as if the seed was an empty string. I guess this is because makeSeedSeq returns a reference to a local and the result is undefined behavior? This is an aside, but if someone could explain this and perhaps why seed_seq was implemented this way, I would very much appreciate it.

Aucun commentaire:

Enregistrer un commentaire