C ++ 11 Совместное использование одной и той же функции с различными типами случайных распределений - PullRequest
0 голосов
/ 01 июня 2018

У меня есть две функции.Единственное отличие этих двух функций заключается в том, что они используют разные генераторы случайных чисел.Для вашего удобства я написал несколько компилируемых кодов, как показано ниже.Это две функции:

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;
}

Ответы [ 4 ]

0 голосов
/ 01 июня 2018

Вы можете создать шаблон базового класса, специализация которого предусматривает другой объект распределения в соответствии с его параметром 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;
}
0 голосов
/ 01 июня 2018

Я предлагаю использовать специализацию шаблонов.

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>();
  }
}
0 голосов
/ 01 июня 2018
#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.Для объекта, определенного в главной функции, вы можете переместить их в пространство имен stackoverflow, но не делать их глобальными.

0 голосов
/ 01 июня 2018

Может быть, я неправильно понимаю, что вы спрашиваете, но не могли бы вы просто использовать перегрузку функций?

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...
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...