c++ - C++ 中简单的类型驱动随机模型构造

标签 c++ boost stub mockups random

C++11 的新 Random 或 Boost.Random 非常酷、强大且灵活,但由于选择了生成器分布播种,使用起来很麻烦 状态处理(进而重入线程安全)等。

然而,通常,在单元测试中创建模型对象时,我们实际上只需要一种简单方法来创建特定类型的随机对象,而不必关心特定参数。我个人认为 C++ STL 和 Boost 缺乏一种简单且可重用的方法来完成此任务。我们真的只想说,例如,

std::vector<uint32_t> x(10);
some_nice_namespace::randomize(x);

使用一些全局状态并且仅在需要时才使用更具体的状态

some_nice_namespace::randomize(x, rng_state);

或者更具体的比如

some_nice_namespace::randomize(x, rng(rng_state));

任何同时使用过 Matlab 和 C/C++ 的人都应该非常清楚这种生产力差距。是否有任何 C++ 库实现了这些想法?如果没有,我会自己实现它们,并可能将它们添加到 Boost。

最佳答案

Boost.Random似乎没有提供将生成器与分布绑定(bind)在一起的类。您可以制作一个将两者绑定(bind)在一起的模板仿函数类。

Boost.ForeachBoost.Range对于编写在任何容器、数组或迭代器对上运行的通用代码很有用。

一旦您定义了一个绑定(bind)生成器和分布的仿函数,我已经提出了以下方法,它允许您简洁地随机化容器。

#include <iostream>
#include <vector>
#include <boost/random.hpp>
#include <boost/foreach.hpp>
#include <boost/range/metafunctions.hpp>
#include <boost/range/algorithm/generate.hpp>

namespace rng // some nice namespace
{

//------------------------------------------------------------------------------
// Binds a generator together with a distribution
template <class D, class G>
struct Functor
{
    typedef D Distribution;
    typedef G Generator;
    typedef typename D::result_type result_type;

    Distribution distribution;
    Generator generator;

    explicit Functor(const D& dist = D(), const G& gen = G())
    : distribution(dist), generator(gen) {}

    result_type operator()() {return distribution(generator);}
};

//------------------------------------------------------------------------------
// Randomizes a collection (range) with the given functor
template <class Range, class Functor>
void randomize(Range& range, Functor& functor)
{
    BOOST_FOREACH(typename boost::range_reference<Range>::type x, range)
    {
        x = functor();
    }
}

} // namespace rng

//------------------------------------------------------------------------------
int main()
{
    namespace brnd = boost::random;
    typedef rng::Functor<brnd::uniform_int_distribution<>, brnd::mt19937> Dice;

    // This object could be made global if desired
    Dice dice(Dice::Distribution(1,6));

    std::vector<int> rolls(10);
    rng::randomize(rolls, dice); // Concise one-liner!

    /*  Could also use the following one-liner, but dice would be passed by
        copy and the resulting RNG state would not be retained. */
    // boost::generate(rolls, dice);

    std::cout << "Rolls:\n";
    BOOST_FOREACH(int roll, rolls)
        std::cout << roll << "\n";
}

通过使用模板特化,您可以为各种数字类型提供默认生成器:

//------------------------------------------------------------------------------
template <typename T>
struct DefaultFunctor
{
    typedef Functor<boost::random::uniform_int_distribution<T>,
                    boost::random::mt19937> Type;
    static T generate() {static Type fn; return fn();}
};

template <>
struct DefaultFunctor<float>
{
    typedef Functor<boost::random::uniform_01<float>,
                    boost::random::mt19937> Type;
    static float generate() {static Type fn; return fn();}
};

template <>
struct DefaultFunctor<double>
{
    typedef Functor<boost::random::uniform_01<double>,
                    boost::random::mt19937> Type;
    static double generate() {static Type fn; return fn();}
};

//------------------------------------------------------------------------------
template <class Range>
void randomize(Range& range)
{
    typedef typename boost::range_value<Range>::type value_type;

    BOOST_FOREACH(typename boost::range_reference<Range>::type x, range)
    {
        x = DefaultFunctor<value_type>::generate();
    }
}

//------------------------------------------------------------------------------
int main()
{
    std::vector<float> noise(10);
    rng::randomize(noise);

    std::cout << "Noise:\n";
    BOOST_FOREACH(float sample, noise)
        std::cout << sample << "\n";
}

关于c++ - C++ 中简单的类型驱动随机模型构造,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8122893/

相关文章:

c++ - 一个类可以通过什么方式访问另一个类的成员?

C++ 捕获所有异常

C++,迭代器问题

c - 什么是 stub 例程?

unit-testing - 在 Node.js 的单元测试中 stub 依赖项

c++ - 当取消请求排队时,pthread_cancel() 将如何响应?

Android Studio 找不到 Boost header

c++ - 如何编写一个可控的随机数生成器?

c++ - string to flyweights 的字符串转换 : Better performance option

java - stub 检查异常 : how to handle the exception