如何从成员初始化列表中调用随机生成器的 seed_seq 构造函数?

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

我有一个 class 和一个 std::mersenne_twister_engine 成员,我想用从字符串构造的 std::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 两次的情况下完成这项工作?

在有人建议之前,我也尝试过使用单独的成员函数来构造 std::seed_seq 对象,但是我可以编译它的唯一方法是返回一个 const ref,如下所示:

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 确实可以编译,但是当使用不同的字符串进行测试时,结果总是相同的,并且总是好像种子是一个空字符串一样。我猜这是因为 makeSeedSeq returns 对本地的引用并且结果是未定义的行为? 这是题外话,但如果有人能解释这一点以及为什么 std::seed_seq 是这样实现的,我将不胜感激。

只需将std::seed_seq变量添加到std::mt19937_64之前的class(变量初始化顺序很重要):

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 复制构造函数。