我正在编写一个包含
list<T>
的程序,其中 T
是 int
或 double
。我想创建一个函数,使用标题 <random>
中的组件,生成 T
类型的数字。我找不到以 T
作为模板参数的分布。
该函数将用于调用
generate
函数:
generate(myList.begin(), myList.end(), RandomGenerator())
我该怎么做?
我尝试创建一个名为
RandomGenerator
的类并为其重载 operator()
。
当我尝试将参数传递给重载的 operator()
时,我收到错误。
函数调用,
Random(b)
是一个函数对象,带有int
参数b
:
generate(rList.begin(), rList.end(), Random(b));
用于重载
()
的代码,其中 n
是一种“虚拟”变量,用于仅告诉它是什么类型:
int operator()(int n)
{
std::uniform_int_distribution<int> dist(1000, 2000);
return dist(gen);
}
错误信息:
Error 2 error C2440: '<function-style-cast>' : cannot convert from 'int' to 'Random'
Error 3 error C2780: 'void std::generate(_FwdIt,_FwdIt,_Fn0)' : expects 3 arguments - 2 provided
除了 Joey 的回答之外,以下内容应该与
std::generate
配合得很好。免责声明:我不擅长元编程,请指出任何错误或可能的改进。这是一个 C++11 解决方案,使用 C++14 会更短一些。
#include <algorithm>
#include <iostream>
#include <list>
#include <random>
#include <type_traits>
template<typename T,
typename = typename std::enable_if<std::is_arithmetic<T>::value>::type>
class random_generator {
using distribution_type = typename std::conditional<
std::is_integral<T>::value,
std::uniform_int_distribution<T>,
std::uniform_real_distribution<T>
>::type;
std::default_random_engine engine;
distribution_type distribution;
public:
auto operator()() -> decltype(distribution(engine)) {
return distribution(engine);
}
};
template<typename Container, typename T = typename Container::value_type>
auto make_generator(Container const&) -> decltype(random_generator<T>()) {
return random_generator<T>();
}
int main() {
auto l = std::list<double>(10);
std::generate(std::begin(l), std::end(l), make_generator(l));
for (auto i : l) {
std::cout << i << " ";
}
}
不是一个优雅的解决方案,但可以满足您的要求:(修改代码以便可以与生成一起使用)
template <typename Distribution>
class RandomGenerator
{
using Type = typename Distribution::result_type;
const Type getRandom(const Type& lower, const Type& upper) const
{
static std::default_random_engine generator;
static Distribution distribution(lower, upper);
return distribution(generator);
}
public:
RandomGenerator(const Type& lowerBound, const Type& upperBound) : _lowerBound(lowerBound), _upperBound(upperBound) { }
const Type operator()() const
{
return getRandom(_lowerBound, _upperBound);
}
private:
Type _lowerBound;
Type _upperBound;
};
int main()
{
RandomGenerator<std::uniform_int_distribution<>> randomIntGenerator(1, 10);
RandomGenerator<std::uniform_real_distribution<>> randomDoubleGenerator(0.0, 10.0);
std::deque<int> intRandoms(10);
std::generate(intRandoms.begin(), intRandoms.end(), randomIntGenerator);
std::deque<double> doubleRandoms(5);
std::generate(doubleRandoms.begin(), doubleRandoms.end(), randomDoubleGenerator);
return 0;
}
当然,如果我们希望每次运行都有不同的数字,我们可以将 default_random_engine 的种子设置为类似 time(0) 的值,但我会忽略这个。
这是我的尝试(警告:我只是写了它)。它支持
bool
和整数类型,但不支持 double
(尽管这很容易添加)。它对返回类型使用类型推导。
#include <iostream>
#include <random>
#include <cstdint>
template<typename PRNG>
class Random
{
public:
Random(PRNG& prng) : m_prng(prng) {}
operator bool() const {
return (m_prng() & 1) != 0;
}
template<
typename T,
typename = typename std::enable_if_t<std::is_integral_v<T>>
>
operator T() const {
return std::uniform_int_distribution<T>()(m_prng);
}
private:
PRNG& m_prng;
};
int main() {
for (unsigned i = 0; i < 100; ++i) {
std::mt19937_64 prng(i);
bool x = Random(prng);
uint8_t y = Random(prng);
uint32_t z = Random(prng);
std::cout << x << " " << int(y) << " " << z << std::endl;
}
}