我有两个功能。这两个函数的唯一区别是它们使用不同的随机数生成器。为方便起见,我写了一些可编译的代码,如下所示。这两个功能是
fillRandomVecInt
和
fillRandomVecNorm
我们如何将这两个功能合二为一?我可以使用指向基类的指针并动态连接rnorm
和runifInt
吗?或使用模板来解决此问题?非常感谢你的帮助。
#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;
}
答案 0 :(得分:3)
我建议使用模板专业化。
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>();
}
}
答案 1 :(得分:1)
也许我误解了你的要求,但你不能只使用函数重载吗?
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...
}
}
答案 2 :(得分:0)
#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命名空间中,但不要将它们全局化。
答案 3 :(得分:0)
您可以模拟基类,该基类的特化根据其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;
}