Как вызвать конструктор seed_seq случайного генератора из списка инициализации члена? - PullRequest
0 голосов
/ 24 октября 2018

У меня есть класс с членом mersenne_twister_engine, который я хочу инициализировать с помощью seed_seq, созданного из строки.Сначала я попробовал это:

class A
{
private:
    std::mt19937_64 rng;

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

Но это не компилируется, потому что:

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

Я могу заставить его работать так:

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);
    }
};

Но если я правильно понимаю, переменная-член rng теперь будет построена дважды, поэтому, если возможно, я бы хотел этого избежать. Итак, мой главный вопрос: Возможно ли сделать эту работу без инициализации rng дважды?

Прежде чем кто-либо предлагает, я также пытался использовать отдельный членфункция для создания объекта seed_seq, но единственный способ, которым я могу заставить его скомпилировать, - это вернуть константную ссылку следующим образом:

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)) { }
};

Класс C выполняет компиляцию, но при тестировании с разными строками результатывсегда то же самое и всегда, как если бы семя было пустой строкой.Я думаю, это потому, что makeSeedSeq возвращает ссылку на локальный, и результатом является неопределенное поведение? Это отступление , но если бы кто-то мог объяснить это и, возможно, почему seed_seq был реализован таким образом, я был бы очень признателен.

1 Ответ

0 голосов
/ 25 октября 2018

Просто добавьте std::seed_seq переменную в класс до std::mt19937_64 (порядок инициализации переменных важен):

class A
{
private:
    std::seed_seq seed_seq;
    std::mt19937_64 rng;

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

    std::uint32_t uniform()
    {
        return std::uniform_int_distribution<std::uint32_t>()(rng);
    }
};

Также я бы предложил использовать const& в конструкторе, чтобы избежать std::string Копировать конструктор выполнения.

...