C ++ 11 std库有几个随机数生成器(RNG),每个生成器实现概念UniformRandomNumberGenerator。然后可以将它们用作随机分布的参数,另请参阅this documentation以获取概述。
这种设计的优点是底层RNG引擎的选择与其应用分离。但是,该设计还要求对RNG的所有调用的定义(不仅仅是声明)是可用的(如果RNG类型仍未指定为模板参数)。因此,在
struct complicated_random_distribution
{
/*
some data and auxiliary methods here
*/
// complicated; may call RNG::operator() many times
template<typename RNG>
some_type operator()(RNG&gen) const;
};
成员operator()
不能在单独的编译单元(CU)中直接实现,但必须在同一个头文件中(或者从#include
d)中提供。
对于单独的实现,理想情况下需要某种方式来打包RNG,方式与std::function<>
打包任何可调用对象的方式相同。
(仅使用std::function
并提供RNG::min()
和RNG::max()
的值作为单独CU中定义的函数的参数是限制性的,并且不允许使用,例如std::uniform_real_distribution<>
内侧)。
如何做到这一点?这个实现是否可用? std库将来会提供这个吗?还是我在吃了一只红鲱鱼?
编辑随机数生成器需要有static
个成员min()
和max()
,使得类型擦除变得困难或不可能(GNU的libstdc ++不会这个假设和非静态成员min()
和max()
的类型擦除有效,但不适用于LLVM的libc ++,后者使用标准的static
成员。还有办法还能解决这个问题吗?如果没有,这是否意味着C ++标准对随机数生成器有一个拙劣的界面?
答案 0 :(得分:2)
使用independent_bits_engine
调整RNG,并键入擦除适应的RNG。您完全了解independent_bits_engine
&#39; min()
和max()
是什么。
这是草图:
struct RNG_wrapper {
using result_type = std::uint32_t;
static constexpr result_type min() { return 0; }
static constexpr result_type max() { return 0xFFFFFFFF; }
template<class RNG>
using my_engine_type = std::independent_bits_engine<RNG, 32, result_type>;
template<class RNG,
class = std::enable_if_t<!std::is_same<std::decay_t<RNG>, RNG_wrapper>{}>>
RNG_wrapper(RNG&& r)
: rng(my_engine_type<std::decay_t<RNG>>(std::forward<RNG>(r))) {}
result_type operator()() { return rng(); }
std::function<result_type()> rng;
};
答案 1 :(得分:1)
这适用于clang和gcc(使用libstdc ++),但这不是严格意义上的UniformRandomNumberGenerator
,因为min
和max
不是静态的。
#include <cassert>
#include <random>
#include <functional>
#include <iostream>
template<typename T>
class AnyUniformRandomNumberGenerator
{
T mMin;
T mMax;
std::function<T()> mValue;
public:
using result_type = T;
template<typename UniformRandomNumberGenerator>
AnyUniformRandomNumberGenerator(UniformRandomNumberGenerator uniformRandomNumberGenerator) :
mMin(UniformRandomNumberGenerator::min()),
mMax(UniformRandomNumberGenerator::max()),
mValue([=]() mutable { return uniformRandomNumberGenerator(); })
{}
T operator()()
{
return mValue();
}
T min()
{
return mMin;
}
T max()
{
return mMax;
}
};
int main()
{
std::default_random_engine rng;
AnyUniformRandomNumberGenerator<decltype(rng())> any{rng};
assert(any() <= any.max());
assert(any() >= any.min());
std::uniform_int_distribution<> dist{1, 6};
std::cout << dist(any);
}