这里得出的结论是,最好绕过<条码>:见d_seq。 当你拥有真正随机的原始数据来源时。
关于许多系统,但也许并非所有系统,st:random_device
属于此种来源。 其潜在的陷阱是众所周知的。 这一答案假设,<代码>t:random_device得出的数值确实是随机的。
另一项结论是,使用<代码>operator>>在问题中提出的解决办法是次优。 这一解决办法按现有标准运作,但<代码>的间接费用如下:斯特罗门代码>不必要地放慢。 更好的解决办法是,创建一种直接产生种子的习俗(>>,见d_seq
,而不必将其序列化,然后通过std:stringstream
。
根据@Sam Mason 和@Severin Pappadeux 的想法,我上课,执行<代码>完整接口:见d_seq。
它不使用概念或SFINAE强制执行对其模板论点的任何要求。 除此以外,我认为它符合C++标准界定的种子序列的所有要求。
功能seed_randomly
现已成为模板,与C++的任何随机编号发动机合作。 标准图书馆。
More precisely, it works with any random number engine that has a
templated member function seed(sseq)
. If, however, function
seed(sseq)
is not templated, and instead has its parameter
hard-coded as std::seed_seq
, then seed_randomly
will fail,
because it will be unable to convert tbx::seed_seq_rd
into
std::seed_seq
.
I tested with MSVC, and was able to seed all of the engines from
the standard library, as well as a couple of PCG implementations
I coded myself.
The following is a mini-test program that seeds both std::mt19937
and std::mt19937_64
. It is a complete program, so you should be
able to copy, paste, and compile without any need to fiddle. I had my compiler set to C++14.
#include <array> // array
#include <cstddef> // size_t
#include <initializer_list> // initializer_list
#include <random> // mt19937, random_device
#include <iostream> // cout, ostream_iterator (used only in main)
namespace tbx
{
class seed_seq_rd
{
// This class mimics the interface of std::seed_seq, but
// uses std::random_device to generate seeds.
//
// It does not use concepts or SFINAE to enforce any
// requirements on its template arguments. Other than that,
// it complies with all requirements of a seed sequence as
// defined in the C++ standard.
public:
using result_type = typename std::random_device::result_type;
private:
// No matter what ctor you use, all you get is this array
// with one element. Best practice, therefore, is to use the
// default ctor.
enum : std::size_t { zero, one };
std::array<result_type, one> seeds{};
public:
seed_seq_rd() noexcept
= default;
template <typename InputIt>
seed_seq_rd(InputIt begin, InputIt end)
{}
template <typename T>
seed_seq_rd(std::initializer_list<T> li)
{}
seed_seq_rd(seed_seq_rd const&)
= delete;
seed_seq_rd& operator=(seed_seq_rd const&)
= delete;
template <typename RandomIt>
void generate(RandomIt begin, RandomIt end)
{
std::random_device rd;
while (begin != end)
{
*begin = rd();
++begin;
}
}
template <typename OutputIt>
void param(OutputIt dest) const
{
*dest = seeds.front();
}
auto size() const noexcept
{
return seeds.size();
}
};
template <typename RandomEngine>
void seed_randomly(RandomEngine& e)
{
tbx::seed_seq_rd s;
e.seed(s);
}
}
int main()
{
std::mt19937 mt;
std::cout << "std::mt19937 - Default seeding:
" << mt << "
";
tbx::seed_randomly(mt);
std::cout << "std::mt19937 - Random seeding:
" << mt << "
";
tbx::seed_randomly(mt);
std::cout << "std::mt19937 - A different random seeding:
" << mt << "
";
std::mt19937_64 mt64;
std::cout << "std::mt19937_64 - Default seeding:
" << mt64 << "
";
tbx::seed_randomly(mt64);
std::cout << "std::mt19937_64 - Random seeding:
" << mt64 << "
";
tbx::seed_randomly(mt64);
std::cout << "std::mt19937_64 - A different random seeding:
" << mt64 << "
";
// Other ctors work, but there is no reason to use anything
// but the default ctor.
{
std::array<int, 10> primes{ 1, 3, 5, 7, 11, 13, 17, 19, 23, 29 };
tbx::seed_seq_rd s(std::cbegin(primes), std::cend(primes));
std::cout
<< "tbx::seed_seq_rd - Construct from iterator range:
"
<< "sseq.size(): " << s.size()
<< "
sseq.param(): ";
s.param(std::ostream_iterator
<tbx::seed_seq_rd::result_type>(std::cout, " "));
std::cout << "
";
}
{
tbx::seed_seq_rd s{ -1ll, 0ll, 1ll };
std::cout
<< "tbx::seed_seq_rd - Construct from std::initializer_list<long long>:
"
<< "sseq.size(): " << s.size()
<< "
sseq.param(): ";
s.param(std::ostream_iterator
<tbx::seed_seq_rd::result_type>(std::cout, " "));
std::cout << "
";
}
return 0;
}