int和double的统一随机分布“基类”?

时间:2015-10-02 12:32:35

标签: c++ random function-pointers distribution functor

我正在尝试创建一个用随机数填充列表的函数,并根据列表项的类型生成整数或浮点数。到目前为止,我已经提出了以下代码,它可以工作:

template <typename T>
void generateRandom(list<T>& numberList){
    default_random_engine randomGenerator(random_device{}());

    if( typeid(T) == typeid(int) ){
        uniform_int_distribution<T> distribution(1000, 2000);
        auto myGenerator = bind(distribution, randomGenerator);
        generate(numberList.begin(), numberList.end(), myGenerator);
    }
    else if( typeid(T) == typeid(double) ){
        uniform_real_distribution<T> distribution(1000.0, 2000.0);
        auto myGenerator = bind(distribution, randomGenerator);
        generate(numberList.begin(), numberList.end(), myGenerator);
    }
    else{
        return;
    }

}

但是,我对此解决方案并不满意。只是感觉应该有一些方法可以突破除IF语句中的实际分布之外的所有内容。类似的东西:

template <typename T>
void generateRandom(list<T>& numberList){
    default_random_engine randomGenerator(random_device{}());

    X distribution;
    if( typeid(T) == typeid(int) )
        distribution = uniform_int_distribution<T>(1000, 2000);
    else if( typeid(T) == typeid(double) )
        distribution = uniform_real_distribution<T>(1000.0, 2000.0);
    else
        return;

    auto myGenerator = bind(distribution, randomGenerator);
    generate(numberList.begin(), numberList.end(), myGenerator);
}

(X是这里缺少的占位符)

但由于uniform_int_distributionuniform_real_distribution没有共同的基类,这怎么可能呢?我试过玩函数指针和仿函数,但我似乎从来没有超过IF语句,这很烦人。这可以用更优雅的方式解决吗?

注意:这是学校作业的一部分,我们必须使用generate()<random>函数和模板来生成随机数。我认为我的原始解决方案是可以接受的,我只是不喜欢IF语句中那些重复代码行的外观...:)

3 个答案:

答案 0 :(得分:2)

您可以创建类似于类型的类:

template<class T>
struct Distribution {};

template<>
struct Distribution<int> {
    typedef uniform_int_distribution<int> type;
};

template<>
struct Distribution<double> {
    typedef uniform_real_distribution<double> type;
};

template <typename T>
void generateRandom(list<T>& numberList){
    default_random_engine randomGenerator(random_device{}());

    typename Distribution<T>::type distribution = typename Distribution<T>::type(1000, 2000);
    ...

另一种选择是创建一个模板助手函数,它将接受所需的分布作为参数:

template<class T, template<class> class Distr>
void generateRandomHelper(list<T>& numberList){
    default_random_engine randomGenerator(random_device{}());

    Distr<T> distribution = Distr<T>(1000, 2000);

    auto myGenerator = bind(distribution, randomGenerator);
    generate(numberList.begin(), numberList.end(), myGenerator);
}

template<class T>
void generateRandom2(list<T>& numberList);

template<>
void generateRandom2<int>(list<int>& numberList) {
    generateRandomHelper<int, uniform_int_distribution>(numberList);
}

template<>
void generateRandom2<double>(list<double>& numberList) {
    generateRandomHelper<double, uniform_real_distribution>(numberList);
}

答案 1 :(得分:2)

您可以使用:

template <typename T>
using my_distribution = std::conditional_t<std::is_integral<T>::value,
                   std::uniform_int_distribution<T>,
                   std::conditional_t<std::is_floating_point<T>::value,
                                      std::uniform_real_distribution<T>,
                                      void>
                   >;

然后

template <typename T>
void generateRandom(list<T>& numberList){
    default_random_engine randomGenerator(random_device{}());
    my_distribution<T> distribution(1000, 2000);
    auto myGenerator = bind(distribution, randomGenerator);
    generate(numberList.begin(), numberList.end(), myGenerator);
}

答案 2 :(得分:-1)

您正在尝试计算类型。这要求(非常,非常,非常)简单的模板元编程:

template<typename T> class Distribution;
template<> class Distribution<int> {
    using distribution = uniform_int_distribution<int>;
};
template<> class Distribution<double> {
    using distribution = uniform_real_distribution<int>;
};


template <typename T>
void generateRandom(list<T>& numberList){
    default_random_engine randomGenerator(random_device{}());

    Distribution<T>::distribution distribution(1000, 2000);

    auto myGenerator = bind(distribution, randomGenerator);
    generate(numberList.begin(), numberList.end(), myGenerator);
}

当T既不是int也不是double时,此代码无法编译。编译器会抱怨,Distribution<T>::distribution没有T类型。

假设,默默无闻,例如对于float或unsigned int,确实是你需要的:

template<typename T> class Distribution {
public:
    // just anything, so that there is a type
    // not sure if this is really necessary
    using distribution = uniform_int_distribution<int>; 
    static const bool valid = false;
};
template<> class Distribution<int> {
public:
    using distribution = uniform_int_distribution<int>;
    static const bool valid = true;
};
template<> class Distribution<double> {
public:
    using distribution = uniform_real_distribution<double>;
    static const bool valid = true;
};


template <typename T>
void generateRandom(list<T>& numberList){
    default_random_engine randomGenerator(random_device{}());

    if(!Distribution<T>::valid) return;

    Distribution<T>::distribution distribution(1000, 2000);
    auto myGenerator = bind(distribution, randomGenerator);
    generate(numberList.begin(), numberList.end(), myGenerator);
}

现在默认只是默默无效。要实际生成除int或double之外的随机数,您必须专门为您的类型设置模板,就像我为int和double所做的那样。