C++11 与不同类型的随机分布共享相同的函数

C++11 Sharing the same function with different types of random distributions

本文关键字:共享 函数 分布 随机 同类型 C++11      更新时间:2023-10-16

我有两个函数。这两个函数的唯一区别是它们使用不同的随机数生成器。为了您的方便,我编写了一些可编译的代码,如下所示。这两个功能是

fillRandomVecInt

fillRandomVecNorm

我们如何将这两个功能合二为一?我可以使用指向基类的指针并动态挂接rnormrunifInt吗?还是使用模板来解决此问题?非常感谢您的帮助。

#include <iostream>
#include<random>
using namespace std;
class RandomVec{
private:
unsigned seed = 0;
std::default_random_engine generator{seed};
std::normal_distribution<> rnorm{0,1};
std::uniform_int_distribution<> runifInt{0,1};
public:
void fillRandomVecInt(vector<int> & v);
void fillRandomVecNorm(vector<double> & v);
};
void RandomVec::fillRandomVecNorm(vector<double> &v) {
for(auto i=v.begin();i!=v.end();++i){
*i=rnorm(generator);
}
}
void RandomVec::fillRandomVecInt(vector<int> &v) {
for(auto i=v.begin();i!=v.end();++i){
*i=runifInt(generator);
}
}

int main() {
RandomVec rv;
vector<double> x=vector<double>(10);
rv.fillRandomVecNorm(x);
vector<int> y = vector<int>(10);
rv.fillRandomVecInt(y);
return 0;
}

我建议使用模板专业化。

class RandomVec {
private:
unsigned seed = 0;
std::default_random_engine generator{seed};
std::normal_distribution<> rnorm{0, 1};
std::uniform_int_distribution<> runifInt{0, 1};
template<typename T>
T generateRandom(void);
public:
template<typename T>
void fillRandomVec(vector<T> &v);
};
template<>
int RandomVec::generateRandom(void) {
return runifInt(generator);
}
template<>
double RandomVec::generateRandom(void) {
return rnorm(generator);
}
template<typename T>
void RandomVec::fillRandomVec(vector<T> &v) {
for (auto i = v.begin(); i != v.end(); ++i) {
*i = generateRandom<T>();
}
}

也许我误解了你在问什么,但你不能只使用函数重载吗?

void fillRandomVec(vector<int>& v) {
//code...
}
void fillRandomVec(vector<double>& v {
//code...
}

或。。。

//this is a function I have used that I copied in
template<class T>
bool vectIsInt(std::vector<T>& v)
{
for (int i = 0; i < v.size(); i++)
{
if (v[i] != floor(v[i]) return false;
}
return true;
}
template<class U>
void fillRandomVec(std::vector<U>& v)
{
if (vectIsInt(v))
{
//code if int vect
}
else
{
//code if double vect...
}
}
#include<time.h>
#include<algorithm>
#include<functional>
#include <iostream>
#include<random>
using namespace std;
namespace stackoverflow
{
//just for this topic
template<typename _FwdIt,typename _RngFn>
void random_fill(_FwdIt first, _FwdIt last, _RngFn&& fn)
{   //random fill the range [first,last) by means of fn
_DEBUG_RANGE(first, last);
generate(first, last, fn);
}
}
//random function-fn is provided by yourself, for example
int main() {
using namespace stackoverflow;
static default_random_engine e(time(0));
std::normal_distribution<> rnorm{ 0,1 };
std::uniform_int_distribution<> runifInt{ 0,1 };
std::uniform_int_distribution<> runifInt_1{ 2,10 };
std::uniform_real_distribution<> runifDouble{ 0,1 };
vector<int> x(10);
//type int can be random fill throw normal or uniform distribution or other, and 
//some distribution parameter can change
random_fill(x.begin(), x.end(), bind(ref(runifInt),ref(e)));
random_fill(x.begin(), x.end(), bind(ref(runifInt_1), ref(e)));
random_fill(x.begin(), x.end(), bind(ref(rnorm), ref(e)));
vector<double> y(10);
//type double can be random fill throw normal or uniform distribution or other, and
//some distribution parameter can change
random_fill(y.begin(), y.end(), bind(ref(rnorm),ref(e)));
random_fill(y.begin(), y.end(), bind(ref(runifDouble), ref(e)));
return 0;
}

我认为STL算法是最有帮助的,所以我设计了这些变异的STL。 对于 main 函数中定义的对象,您可以根据需要将它们移动到 stackoverflow 命名空间中,但不要将它们全局移动。

您可以模板化基类,该基类的专用化根据其 typename 参数提供不同的分发对象。

然后,对于要支持的每种类型,只需要少量代码,这些代码专用于具有相应分发对象的类模板。

这种方法的一个优点是,一个专用基类可以支持多个typename T。例如,在下面的示例中,支持所有整型(不仅仅是int(和浮点(不仅仅是double(类型。

请参阅下面的代码:

#include <iostream>
#include<random>
using namespace std;
namespace {
// Helper type defined since C++14.
template<bool B, class T = void>
using enable_if_t = typename std::enable_if<B,T>::type;
}
// Base class to be specialized with different distribution object.
template<typename T, typename Enable = void>
class RandomVecBase;
// Supports integers with uniform_int_distribution
template<typename T>
class RandomVecBase<T, enable_if_t<std::is_integral<T>::value> > {
public:
RandomVecBase() : distrib_{0, 1} {}
protected:
uniform_int_distribution<> distrib_;
};
// Supports floating-point with normal_distribution.
template<typename T>
class RandomVecBase<T, enable_if_t<std::is_floating_point<T>::value> > {
public:
RandomVecBase() : distrib_{0, 1} {}
protected:
normal_distribution<> distrib_;
};
// Actual class, code in fillRandomVec() only needs to be written once
template<typename T>
class RandomVec : public RandomVecBase<T> {
private:
unsigned seed = 0;
default_random_engine generator{seed};
public:
void fillRandomVec(vector<T>& v) {
for (auto& i : v) {
i = this->distrib_(generator);
}
}
};

int main() {
RandomVec<double> rv_double;
vector<double> x = vector<double>(10);
rv_double.fillRandomVec(x);
RandomVec<int> rv_int;
vector<int> y = vector<int>(10);
rv_int.fillRandomVec(y);
return 0;
}