pack(类型擦除)随机数生成器

时间:2015-06-01 10:28:25

标签: c++ c++11 random

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 ++标准对随机数生成器有一个拙劣的界面?

2 个答案:

答案 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,因为minmax不是静态的。

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

GCC: http://rextester.com/ANAP79935

http://rextester.com/YCIIR21607