2014-10-06 42 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