Boost.Random , похоже, не предоставляет класс, который связывает генератор вместе с дистрибутивом. Вы можете создать шаблонный класс функторов, который связывает их вместе.
Boost.Foreach и Boost.Range полезны для написания универсального кода, который работает с любым контейнером, массивом или парой итераторов.
Я придумал следующее, которое позволяет вам кратко рандомизировать контейнер, как только вы определили функтор, который связывает генератор и распределение.
#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";
}