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.
答案 0 :(得分:2)
只需将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
复制构造函数。