C++ 模板类中的动态模板方法选择

C++ 模板类中的动态模板方法选择,c++,c++17,C++,C++17,我想创建一个模板随机数生成器类,它可以是整数类型,也可以是浮点类型。为什么?对于赋值,我编写了一个累积函数(本质上与std::acculate相同),我想制作一个可以是任意整数或浮点类型的测试工具(例如,无符号| short | long | long long int、float、double)。我们一直在研究模板,我试图通过使用模板编程来做出动态编译时决策。我可能用了错误的方法来处理这个问题-非常感谢任何建议/参考 下面是我的测试函数: void testdrive() { std:

我想创建一个模板随机数生成器类,它可以是整数类型,也可以是浮点类型。为什么?对于赋值,我编写了一个累积函数(本质上与std::acculate相同),我想制作一个可以是任意整数或浮点类型的测试工具(例如,无符号| short | long | long long int、float、double)。我们一直在研究模板,我试图通过使用模板编程来做出动态编译时决策。我可能用了错误的方法来处理这个问题-非常感谢任何建议/参考

下面是我的测试函数:

void testdrive() {
    std::vector<int> vint(ELEMENTS);
    std::vector<double> vflt(ELEMENTS);
    RNG<int> intrng;
    RNG<double> fltrng;

    std::generate(vint.begin(), vint.end(), intrng)
    std::generate(vflt.begin(), vflt.end(), fltrng)

    std::cout << "Sum of " << printvec(vint) << "is " accum(vint) << "\n\n";
    std::cout << "Sum of " << printvec(vflt) << "is " accum(vflt) << '\n';
}
void testdrive(){
std::向量vint(元素);
std::向量vflt(元素);
RNG intrng;
RNG外研社;
std::generate(vint.begin()、vint.end()、intrng)
std::generate(vflt.begin()、vflt.end()、fltrng)
std::cout看一看。在下面的代码中,私有
struct发行版
选择要使用的
std::uniform\u*\ u发行版

#include <stdio.h>
#include <vector>
#include <algorithm>
#include <random>
#include <iostream>

template <class T>
class RNG
{
    // primary template is designed for integers
    template <class U>
    struct Distribution
    {
        typedef std::uniform_int_distribution<U> Type;
    };
    // explicit specialization for float
    template <>
    struct Distribution<float>
    {
        typedef std::uniform_real_distribution<float> Type;
    };
    // explicit specialization for double
    template <>
    struct Distribution<double>
    {
        typedef std::uniform_real_distribution<double> Type;
    };

    std::random_device rng_source;
    typename Distribution<T>::Type rng_dist;

public:
    RNG(
        T low = std::numeric_limits<T>::min(),
        T high = std::numeric_limits<T>::max())
        : rng_source{}
        , rng_dist(low, high)
    {
    }
    RNG(const RNG& rhs)
        : rng_source{}
        , rng_dist(rhs.rng_dist)
    {
    }

    T operator()()
    {
        return rng_dist(rng_source);
    }
};

int main()
{
    const size_t ELEMENTS = 10;
    std::vector<int> vint(ELEMENTS);
    std::vector<double> vflt(ELEMENTS);
    RNG<int> intrng(0, 100);
    RNG<double> fltrng(0.0, 1.0);

    std::generate(vint.begin(), vint.end(), intrng);
    std::generate(vflt.begin(), vflt.end(), fltrng);

    return 0;  <-- set a breakpoint here to see both vectors
}
#包括
#包括
#包括
#包括
#包括
模板
类RNG
{
//主模板是为整数设计的
模板
结构分布
{
typedef std::统一内部分布类型;
};
//float的显式专门化
模板
结构分布
{
typedef std::统一实分布类型;
};
//双精度的显式专门化
模板
结构分布
{
typedef std::统一实分布类型;
};
std::随机_设备rng_源;
类型名称分布::类型rng_dist;
公众:
RNG(
T low=std::numeric_limits::min(),
T high=std::numeric_limits::max())
:rng_源{}
,rng_区(低、高)
{
}
RNG(施工RNG和rhs)
:rng_源{}
,北九龙区(右九龙区)
{
}
T运算符()()
{
返回rng\U dist(rng\U源);
}
};
int main()
{
常量大小元素=10;
std::向量vint(元素);
std::向量vflt(元素);
RNG-intrng(01100);
RNG外语(0.0,1.0);
std::generate(vint.begin()、vint.end()、intrng);
std::generate(vflt.begin(),vflt.end(),fltrng);

返回0;以下是我的想法,但我更喜欢@fifoforlifo的答案:

template<typename T>                                                      
class RNG {                                                               
    static_assert(std::is_arithmetic<T>::value,                           
                  "Only primitive numeric types supported.");             
    public:                                                               
        RNG(T low=std::numeric_limits<T>::min(),                          
            T high=std::numeric_limits<T>::max())                         
            : rng_engine{rng_seed()}, rng_dist{low, high}, rng_low{low},  
              rng_high{high} { }                                          
        RNG(const RNG& r): rng_engine{rng_seed()}, rng_dist{r.rng_low,    
            r.rng_high}, rng_low{r.rng_low}, rng_high{r.rng_high} { }     
        T max() { return rng_dist.max(); }                                
        T min() { return rng_dist.min(); }                                
        T operator()() { return rng_dist(rng_engine); }                   
    private:                                                              
        std::random_device rng_seed;                                      
        std::mt19937 rng_engine;                                          
        std::uniform_int_distribution<T> rng_dist;                        
        T rng_low, rng_high;                                              
};                                                                        

// Specialize RNG                                                         
// Really want a generic way to support any floating point type           
// e.g., float, double, long double                                       
// And ideally this would all be in one template class...                 
template<>                                                                
class RNG<double> {                                                       
    public:                                                               
        RNG(double low=std::numeric_limits<double>::min(),                
            double high=std::numeric_limits<double>::max())               
            : rng_engine{rng_seed()}, rng_dist{low, high}, rng_low{low},  
              rng_high{high} { }                                          
        RNG(const RNG& r): rng_engine{rng_seed()}, rng_dist{r.rng_low,    
            r.rng_high}, rng_low{r.rng_low}, rng_high{r.rng_high} { }     
        double max() { return rng_dist.max(); }                           
        double min() { return rng_dist.min(); }                           
        double operator()() { return rng_dist(rng_engine); }              
    private:                                                              
        std::random_device rng_seed;                                      
        std::mt19937 rng_engine;                                          
                std::uniform_real_distribution<double> rng_dist;          
        double rng_low, rng_high;                                         
};                                                                        
模板
类RNG{
静态_断言(std::is_算术::值,
“仅支持基本数字类型。”);
公众:
RNG(T低=标准::数值限制::最小(),
T high=std::numeric_limits::max())
:rng_引擎{rng_seed()},rng_dist{low,high},rng_low{low},
rng_high{high}{}
RNG(const RNG&r):RNG_引擎{RNG_seed()},RNG_dist{r.RNG_low,
r、 rng_high},rng_low{r.rng_low},rng_high{r.rng_high}
T max(){return rng_dist.max();}
T min(){return rng_dist.min();}
T运算符(){return rng_dist(rng_引擎);}
私人:
std::随机_设备rng_种子;
标准:mt19937燃气轮机;
标准:统一国际分布区域;
温度低,温度高;
};                                                                        
//专门化
//真的想要一种通用的方式来支持任何浮点类型吗
//例如,浮动、双人、长双人
//理想情况下,这些都在一个模板类中。。。
模板
类RNG{
公众:
RNG(双低=标准::数值限制::最小(),
双高=标准::数值限制::最大值()
:rng_引擎{rng_seed()},rng_dist{low,high},rng_low{low},
rng_high{high}{}
RNG(const RNG&r):RNG_引擎{RNG_seed()},RNG_dist{r.RNG_low,
r、 rng_high},rng_low{r.rng_low},rng_high{r.rng_high}
double max(){return rng_dist.max();}
double min(){return rng_dist.min();}
双运算符(){return rng_dist(rng_引擎);}
私人:
std::随机_设备rng_种子;
标准:mt19937燃气轮机;
标准:均匀真实分布区域;
双rng_低,rng_高;
};                                                                        

为什么要这样做?为什么要将生成器与分发捆绑在一起,并将分发绑定到与之没有关联的类型?特别是考虑到
uniform\u int
uniform\u real
没有相同的行为(后者提供半开放的范围,而前者是封闭的范围)。@Nicolas谢谢你的关注。我修改了我的问题,希望能回答你的问题。如果没有,请告诉我。太棒了,这比我自己发现的要好得多。
template<typename T>                                                      
class RNG {                                                               
    static_assert(std::is_arithmetic<T>::value,                           
                  "Only primitive numeric types supported.");             
    public:                                                               
        RNG(T low=std::numeric_limits<T>::min(),                          
            T high=std::numeric_limits<T>::max())                         
            : rng_engine{rng_seed()}, rng_dist{low, high}, rng_low{low},  
              rng_high{high} { }                                          
        RNG(const RNG& r): rng_engine{rng_seed()}, rng_dist{r.rng_low,    
            r.rng_high}, rng_low{r.rng_low}, rng_high{r.rng_high} { }     
        T max() { return rng_dist.max(); }                                
        T min() { return rng_dist.min(); }                                
        T operator()() { return rng_dist(rng_engine); }                   
    private:                                                              
        std::random_device rng_seed;                                      
        std::mt19937 rng_engine;                                          
        std::uniform_int_distribution<T> rng_dist;                        
        T rng_low, rng_high;                                              
};                                                                        

// Specialize RNG                                                         
// Really want a generic way to support any floating point type           
// e.g., float, double, long double                                       
// And ideally this would all be in one template class...                 
template<>                                                                
class RNG<double> {                                                       
    public:                                                               
        RNG(double low=std::numeric_limits<double>::min(),                
            double high=std::numeric_limits<double>::max())               
            : rng_engine{rng_seed()}, rng_dist{low, high}, rng_low{low},  
              rng_high{high} { }                                          
        RNG(const RNG& r): rng_engine{rng_seed()}, rng_dist{r.rng_low,    
            r.rng_high}, rng_low{r.rng_low}, rng_high{r.rng_high} { }     
        double max() { return rng_dist.max(); }                           
        double min() { return rng_dist.min(); }                           
        double operator()() { return rng_dist(rng_engine); }              
    private:                                                              
        std::random_device rng_seed;                                      
        std::mt19937 rng_engine;                                          
                std::uniform_real_distribution<double> rng_dist;          
        double rng_low, rng_high;                                         
};