当前位置: 首页 > 知识库问答 >
问题:

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

养学
2023-03-14

我想创建一个模板随机数生成器类,它可以是整数类型,也可以是浮点类型。为什么?对于赋值,我编写了一个累积函数(本质上与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';
}

我不知道如何为我的类使用模板编程。我想做的是,如果类型是int类型,使用统一的int分布,如果是float | double使用统一的实分布。我意识到这两者并不是完全可以互换的,但就我所尝试的来说,这很好。这是我的班级:

template<typename T>
class RNG {
    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 operator()() { return rng_dist(rng_engine); }
    private:
        std::random_device rng_seed;
        std::mt19937 rng_engine;
        template<typename U, typename=std::enable_if_t<std::is_integral<T>::value>>
            std::uniform_int_distribution<T> rng_dist;
        template<typename U, typename=std::enable_if_t<std::is_floating_point<T>::value>>
            std::uniform_real_distribution<T> rng_dist;
        T rng_low, rng_high;
};

此外,对于任何阅读这篇文章的人,我发现这本书对深入研究C模板非常有帮助: C模板-完整指南第2版(http://www.tmplbook.com/)

共有2个答案

颜河
2023-03-14

以下是我的想法,但我更喜欢@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;                                         
};                                                                        
弓举
2023-03-14

看看模板专业化。在下面的代码中,私有的结构分布选择要使用的std::uniform_*_distribution

#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
}
 类似资料:
  • 问题内容: 这是我的代码: 它运作良好。但是当我尝试添加这个 我遇到编译器错误:«int MyClass :: DoSomething()»的«>»令牌模板标识«DoSomething <0>»之前的无效显式专门化与任何模板声明都不匹配 我使用g ++ 4.6.1应该怎么做? 问题答案: 不幸的是,如果不对外部模板进行特殊化处理,就不能对作为类模板成员的模板进行特殊处理: C ++ 11 14.7

  • 我们已有的几件: Post 模型定义在 models.py 中,我们有 post_list views.py 和添加的模板中。 但实际上我们如何使我们的帖子出现在我们的 HTML 模板上呢? 因为那是我们所想要的: 获取一些内容 (保存在数据库中的模型) 然后在我们的模板中很漂亮的展示,对吗? 这就是 views 应该做的: 连接模型和模板。 在我们的 post_list 视图 中我们需要获取我们

  • 还尝试在专门化的中进行模板方法专门化: 这一次它编译,但调用原始方法,即 解决方案

  • 亦称: Template Method 意图 模板方法模式是一种行为设计模式, 它在超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。 问题 假如你正在开发一款分析公司文档的数据挖掘程序。 用户需要向程序输入各种格式 (PDF、 DOC 或 CSV) 的文档, 程序则会试图从这些文件中抽取有意义的数据, 并以统一的格式将其返回给用户。 该程序的首个版本仅支持 DOC 文

  • 一、定义 模板方法是基于继承的设计模式,可以很好的提高系统的扩展性。 java中的抽象父类、子类 模板方法有两部分结构组成,第一部分是抽象父类,第二部分是具体的实现子类。 二、示例 Coffee or Tea (1) 把水煮沸 (2) 用沸水浸泡茶叶 (3) 把茶水倒进杯子 (4) 加柠檬 /* 抽象父类:饮料 */ var Beverage = function(){}; // (1) 把水煮沸

  • 问题 定义一个算法的结构,作为一系列的高层次的步骤,使每一个步骤的行为可以指定,使属于一个族的算法都具有相同的结构但是有不同的行为。 解决方案 使用模板方法( Template Method )在父类中描述算法的结构,再授权一个或多个具体子类来具体地进行实现。 例如,想象你希望模拟各种类型的文件的生成,并且每个文件要包含一个标题和正文。 class Document produceDocu