数值型模板参数的应用

目录

  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,数组类模板是简易的线性表数据结构;

 

posted @ 2021-07-18 21:16  PRO_Z  阅读(545)  评论(0编辑  收藏  举报