2014-10-06 43 views
2

我正在編寫一個程序,其中包含list<T>,其中Tintdouble。我想要使​​用標題爲<random>的組件生成一個函數,該函數生成T類型的數字。我無法找到以T作爲模板參數的發行版。生成T類型的隨機數

的功能,然後會在通話中使用的generate功能:

generate(myList.begin(), myList.end(), RandomGenerator()) 

我如何去這樣做呢?

我試圖創建一個名爲RandomGenerator的類,併爲它重載operator()。 當我嘗試通過一個參數超載operator()我得到一個錯誤。

函數調用,Random(b)int參數b一個函數對象:

generate(rList.begin(), rList.end(), Random(b)); 

代碼超載(),其中n是有點「僞」 -variable只是告訴它是什麼類型:

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  
+1

你試過了什麼? (提示:你需要重載函數) – texasbruce 2014-10-06 14:01:12

+0

我想你可能會發現['std :: conditional'](http://en.cppreference.com/w/cpp/types/conditional)和type-class測試如['std :: is_floating_point'](http://en.cppreference.com/w/cpp/types/is_floating_point)和['std :: is_integral'](http://en.cppreference.com/ w/cpp/types/is_integral)在這項工作中很有用。 – WhozCraig 2014-10-06 14:36:36

+0

你聲稱用三個參數調用'generate' - 但編譯器說你只通過了兩個參數。這強烈建議您顯示的代碼不是您實際編譯的代碼。顯示錯誤消息引用的確切行。 – 2014-10-06 14:39:43

回答

3

除了喬伊的回答,以下應該與std::generate搭配很好。免責聲明:我在元編程方面很糟糕,請指出任何錯誤或可能的改進。這是一個C++ 11解決方案,使用C++ 14它會稍微短一些。

Live demo on Coliru

#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 << " ";  
    } 
} 
+0

我喜歡這種方法比我的更多。給一個投票! :) – Wrath 2014-10-06 16:40:52

+2

現在用迭代器:http://coliru.stacked-crooked.com/a/1374159170d7232c – 2014-10-06 17:52:02

3

不是一個完美的解決方案,但你想要做什麼:(修改代碼,以便它可以被用來生成)

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像時間(0),但我會離開那一個。

+1

你應該只使用'typename Distribution :: result_type'。 – 2014-10-06 15:00:46

+0

當然,你是絕對正確的;我們可以消除額外的typename Type參數並引入typedef:typedef typename Distribution :: result_type Type; – Wrath 2014-10-06 15:14:13

+1

如果我可能會建議使用''using'語法而不是'typedef'來獲得更多的C++ 11-ish體驗。另外,這兩種方法都可以做成'const'。 – 2014-10-06 15:18:48