zoukankan      html  css  js  c++  java
  • 数值型模板参数的应用

    目录

      1. 初识数值型模板参数

      2. 数值型模板参数的应用

    1、初识数值型模板参数

      在泛型编程中,数据的值和类型都被参数化。在第二次编译时,编译器会根据模板中的类型参数<实参.>去推导形参的值与类型;也就是说,模板不仅支持值的传递,还支持类型的传递,这就是模板与普通函数的最大区别了。

      模板参数可以是数字型参数,也可以是类型参数;接下来我们以代码来说明什么是数值型模板参数?

    1 template <typename T, int N> 
    2 void func()
    3 {
    4     T a[N];  // 使用模板参数定义局部数组;
    5 }
    6            
    7 func<double, 10>();  // 使用模板时,数值型参数必须是常量,不能是变量;

      代码中 N 就是模板中的数值型参数,当发生函数调用时,这个数值型参数就被初始化为常量 10;

      那么什么才是合法的数值型模板参数呢?

      1. 在发生调用时,变量不能作为数值型模板参数;(在编译时,变量的值还没有唯一确定;如 int a = 10; func<double, a>(); 编译失败

      2. 在模板声明时,浮点数不能作为数值型模板参数;(浮点数本身就不精确;如 template <typename T, double N> 编译失败 

      3. 类对象不能作为数值型模板参数;(类对象的属性包含了1、2 这两点)

      ....

      总之,合法的数值型模板参数必须满足,编译阶段确保数值型模板参数是唯一确定的

    2、数值型模板参数的应用

     1. 用你觉得最高效的方法求 1 + 2 + 3 + ... + N 的值;

       求前N项和的方法有很多,比如 for 循环求取(栈空间、堆空间)、等差数列求和(公式法)、递归求取等等。但是题中明确指定是最高效的求和方法,怎么做呢?接下来我们分别分析这三种方法:

       (1)如果用 for循环、递归求取,会随着项数N的增多,导致程序的执行步骤也会增加;显然这时候公式法就比较合适了;(程序执行的步骤是判断算法执行效率的方式之一)

       (2)但是,如何使求和算法做到最高效呢?试想我们能不能站在内存的角度考虑,如果能将这前N项和的结果直接存储在内存中,当我们需要时,直接从内存中读取是不是会更高效呢。

      有了上面的铺垫,现在我们就带着这种思想去实现这个算法(涉及内容:类模板的完全特化、模板的数值型参数、static 和 const 关键字、递归算法)。

     1 #include <iostream>
     2 #include <string>
     3 
     4 using namespace std;
     5 
     6 template
     7 < int N >
     8 class Sum
     9 {
    10 public:
    11     static const int VALUE = Sum<N-1>::VALUE + N;   // 递归思想:如果知道了前(N-1)项的结果,再加上第N项的结果就可以求出前N项和的结果
    12 };
    13 
    14 /* 定义上述类模板的完全特化实现,实现递归出口 N = 1 */
    15 template
    16 < >
    17 class Sum < 1 >
    18 {
    19 public:
    20     static const int VALUE = 1;
    21 };
    22 
    23 /**
    24 * static const int VALUE = 1;
    25 * 1 用字面量去初始化const常量,编译器会将该常量放入符号表中,当使用该常量时,再从符号表中取出该常量的值;
    26 * 2 static 会把所修饰的变量存储到全局数据区,方便让所有对象共享;
    27 * 3 所以,static const 的组合使用会将符号表放入到全局数据区;
    28 */
    29 
    30 int main()
    31 {
    32     cout << "1 + 2 + 3 + ... + 10 = " << Sum<10>::VALUE << endl;
    33     cout << "1 + 2 + 3 + ... + 100 = " << Sum<100>::VALUE << endl;
    34     
    35     return 0;
    36 }
    37 
    38 /**
    39  * 运行结果:
    40  * 1 + 2 + 3 + ... + 10 = 55
    41  * 1 + 2 + 3 + ... + 100 = 5050
    42  */
    最高效的求和算法(递归+类模板完全特化)

      通过这个案列,我们要学会举一反三,从而写出更高效的程序。

     2. 数组模板类的实现

      (1)栈空间创建数组模板类

      1 // array.hpp 数组模板类文件
      2 #ifndef ARRAY_H
      3 #define ARRAY_H
      4 
      5 #include <iostream>
      6 
      7 template
      8 < typename T, int N >  // 数组元素的类型和大小;
      9 class Array
     10 {
     11     T m_array[N];  // 定义一个实际的数组;
     12 public:
     13     int length();
     14     bool set(int index, T value);
     15     bool get(int index, T& value);
     16     T& operator[] (int index);
     17     T operator[] (int index) const;  // 数组类对象有可能是 const 对象,这个时候就只能调用 const 成员函数,所以要定义这个;const 函数只能返回值,不能返回引用;
     18     void print();
     19     void sort();
     20     virtual ~Array();  // 有可能被继承
     21 };
     22 
     23 template
     24 < typename T, int N >
     25 int Array<T, N>::length()
     26 {
     27     return N;
     28 }
     29 
     30 template
     31 < typename T, int N >
     32 bool Array<T, N>::set(int index, T value)
     33 {
     34     bool ret = (0 <= index) && (index < N);
     35     
     36     if( ret )
     37     {
     38         m_array[index] = value;
     39     }
     40     
     41     return ret;
     42 }
     43 
     44 template
     45 < typename T, int N >
     46 bool Array<T, N>::get(int index, T& value)
     47 {
     48     bool ret = (0 <= index) && (index < N);
     49     
     50     if( ret )
     51     {
     52         value = m_array[index];
     53     }
     54     
     55     return ret;
     56 }
     57 
     58 template
     59 < typename T, int N >
     60 T& Array<T, N>::operator[] (int index)
     61 {
     62     return m_array[index];
     63 }
     64 
     65 template
     66 < typename T, int N >
     67 T Array<T, N>::operator[] (int index) const
     68 {
     69     return m_array[index];
     70 }
     71 
     72 template
     73 < typename T, int N >
     74 void Array<T, N>::print()
     75 {
     76     for(int i=0; i< N; i++)
     77     {
     78         std::cout << m_array[i] << "  ";
     79     }
     80     
     81     std::cout << std::endl;
     82 }
     83 
     84 template
     85 < typename T >
     86 void Swap(T& a, T& b)
     87 {
     88     T c = a;
     89     a = b;
     90     b = c;
     91 }
     92 
     93 template
     94 < typename T, int N >
     95 void Array<T, N>::sort()
     96 {
     97     for(int i=0; i<N; i++)
     98     {
     99         for(int j=i; j<N; j++)
    100         {
    101             if( m_array[i] > m_array[j] )
    102             {
    103                 Swap(m_array[i], m_array[j]);
    104             }
    105         }
    106     }
    107 }
    108 
    109 template
    110 < typename T, int N >
    111 Array<T, N>::~Array()
    112 {
    113 
    114 }
    115 
    116 #endif
    117 
    118 // main.cpp 测试文件
    119 
    120 #include <iostream>
    121 #include <string>
    122 #include "array.hpp"
    123 
    124 using namespace std;
    125 
    126 int main()
    127 {
    128     Array<double, 5> ad;  //  相当于 double[5]
    129     
    130     for(int i=0; i<ad.length(); i++)
    131     {
    132         ad[i] = 100 - i * 0.5;
    133     }
    134     
    135     ad.print(); // 100  99.5  99  98.5  98
    136     ad.sort();  // 升序排列
    137     ad.print(); // 98  98.5  99  99.5  100
    138     
    139     Array<int, 5> ai;  // 相当于 int[5]
    140     
    141     for(int i=0; i<ai.length(); i++)
    142     {
    143         ai[i] = i * i;
    144     }
    145     
    146     ai.print(); // 0  1  4  9  16
    147     
    148     return 0;
    149 }
    栈空间中的数组模板类实现

      (2)堆空间创建数组模板类 

      1 // heapArray.hpp 数组模板类文件
      2 #ifndef HEAPARRAY_H
      3 #define HEAPARRAY_H
      4 
      5 template
      6 < typename T, int N >   // 数组元素的类型和大小;
      7 class HeapArray
      8 {
      9 private:
     10     T* m_pointer;
     11     
     12     HeapArray();
     13     HeapArray(const HeapArray<T, N>& obj);
     14     bool construct();
     15 public:
     16     static HeapArray<T, N>* NewInstance(); 
     17     int length();
     18     bool get(int index, T& value);
     19     bool set(int index ,T value);
     20     T& operator [] (int index);
     21     T operator [] (int index) const;  // 有可能有 const 对象;
     22     HeapArray<T, N>& self();
     23     ~HeapArray();  // 这个时候构造函数是 private 的,也就是 HeapArray 类不希望被继承,所以说没有必要将它声明为 virtual 的;
     24 };
     25 
     26 /* 声明与实现要在同一个文件中 */
     27 
     28 template
     29 < typename T, int N >
     30 HeapArray<T, N>::HeapArray()
     31 {
     32     // 与资源无关的操作
     33 }
     34 
     35 template
     36 < typename T, int N >
     37 bool HeapArray<T, N>::construct()
     38 {   
     39     m_pointer = new T[N];   // 申请内存
     40     
     41     return m_pointer != 0;
     42 }
     43 
     44 template
     45 < typename T, int N >
     46 HeapArray<T, N>* HeapArray<T, N>::NewInstance() 
     47 {
     48     HeapArray<T, N>* ret = new HeapArray<T, N>();
     49     
     50     if( !(ret && ret->construct()) ) 
     51     {
     52         delete ret;
     53         ret = 0;
     54     }
     55         
     56     return ret;
     57 }
     58 
     59 template
     60 < typename T, int N >
     61 int HeapArray<T, N>::length()
     62 {
     63     return N;
     64 }
     65 
     66 template
     67 < typename T, int N >
     68 bool HeapArray<T, N>::get(int index, T& value)
     69 {
     70     bool ret = (0 <= index) && (index < N);
     71     
     72     if( ret )
     73     {
     74         value = m_pointer[index];
     75     }
     76     
     77     return ret;
     78 }
     79 
     80 template
     81 < typename T, int N >
     82 bool HeapArray<T, N>::set(int index, T value)
     83 {
     84     bool ret = (0 <= index) && (index < N);
     85     
     86     if( ret )
     87     {
     88         m_pointer[index] = value;
     89     }
     90     
     91     return ret;
     92 }
     93 
     94 template
     95 < typename T, int N >
     96 T& HeapArray<T, N>::operator [] (int index)
     97 {
     98     return m_pointer[index];
     99 }
    100 
    101 template
    102 < typename T, int N >
    103 T HeapArray<T, N>::operator [] (int index) const
    104 {
    105     return m_pointer[index];
    106 }
    107 
    108 template
    109 < typename T, int N >
    110 HeapArray<T, N>& HeapArray<T, N>::self()
    111 {
    112     return *this;
    113 }
    114 
    115 template
    116 < typename T, int N >
    117 HeapArray<T, N>::~HeapArray()
    118 {
    119     delete[]m_pointer;
    120 }
    121 
    122 #endif
    123 
    124 // main.cpp 测试文件
    125 
    126 #include <iostream>
    127 #include <string>
    128 #include "heapArray.hpp"
    129 
    130 using namespace std;
    131 
    132 int main()
    133 {   
    134     HeapArray<char, 10>* pac = HeapArray<char, 10>::NewInstance();  // 在堆区申请 10 char
    135     
    136     if( pac != NULL )
    137     {
    138         HeapArray<char, 10>& ac = pac->self();
    139         
    140         for(int i=0; i<ac.length(); i++)
    141         {
    142             ac[i] = i + 'a';
    143         }
    144         
    145         for(int i=0; i<ac.length(); i++)
    146         {
    147             cout << ac[i] << " ";
    148         }
    149         
    150         cout << endl;
    151     }
    152     
    153     delete pac;
    154 
    155     
    156     HeapArray<int, 10>* pai = HeapArray<int, 10>::NewInstance();    // 在堆区申请 10 int
    157     
    158     if( pai != NULL )
    159     {
    160         HeapArray<int, 10>& ai = pai->self();
    161         
    162         for(int i=0; i<ai.length(); i++)
    163         {
    164             ai[i] = i + 1;
    165         }
    166         
    167         for(int i=0; i<ai.length(); i++)
    168         {
    169             cout << ai[i] << " ";
    170         }
    171         
    172         cout << endl;
    173     }
    174     
    175     delete pai;
    176     
    177     return 0;
    178 }
    179 /**
    180  * 运行结果:
    181  * a b c d e f g h i j 
    182  * 1 2 3 4 5 6 7 8 9 10
    183  */
    堆空间中的数组模板类实现

     本节总结: 

        1,模板参数可以是数值型参数;

        2,数值型模板参数必须在编译期间唯一确定;

        3,数组类模板是基于数值型模板参数实现的;

        4,数组类模板是简易的线性表数据结构;

  • 相关阅读:
    07四则运算三
    第一阶段冲刺01
    构建之法——阅读笔记01
    四则运算
    Windows32位或64位下载安装配置Scala
    Windows32或64位下载安装配置Spark
    在Hadoop中ResourceManager是干什么的?
    什么是NameNode和DataNode?他们是如何协同工作的?
    Hadoop1和Hadoop2的区别是什么?
    什么是yarn?
  • 原文地址:https://www.cnblogs.com/nbk-zyc/p/12425878.html
Copyright © 2011-2022 走看看