一、数值型参数(类型参数)
1、模板参数可以是数值型参数
2、数值型模板参数的限制
(1)、变量不能作为模板参数
(2)、浮点数不能作为模板参数
(3)、类对象不能作为模板参数
(4)、等等
3、数值型参数的本质
(1)、模板参数是在编译阶段被处理的单元,因此,在编译阶段必须准确无误唯一确定
#include <iostream> #include <string> using namespace std; template < typename T, int N> void func() { T a[N] = {0}; for (int i=0; i<N; i++) { a[i] = i; } for (int i=0; i<N; i++) { cout << a[i] << endl; } } template <int N> class Sum { public: //注意以下语句采用递归定义,即当调用Sum<N>::VALUE时, //编译器认为其值等于Sum<N-1>::VALUE + N;于是就出现了 //递归,直至Sum<1>时会找到后面特化的类模定义,因那里 //Sum<1>::VALUE=1,于是递归结束。 //注意,在这程中,会依次产生Sum<100>、Sum<99>、...、Sum<1> //等100个类,而每个类里面都有一个静态成员变量VALUE值,因其 //位于不同的类中,本质上在静态数据中会开辟100多个int型空间 //来存储这些变量。在编译器会进行优化,把中间这些不用的类给 //丢弃,最保存最终的结果,即内存中只有一个静态VALUE变量的值。 static const int VALUE = Sum<N-1>::VALUE + N; }; template<> class Sum<1> { public: //以下语句在声明和定义起并对VALUE进行了初始化。这是合法的 //1. 如果只有单独的static int VALUE为什么不能直接初始化? // 因为C++里声明和定义是分开的,当编译器看到那样的语句时 // 会认为这是声明,并没有定义,也就是空间还没分配好,需要在
//类的外部先另外分配空间才能初始化
//2. 如果只有const int VALUE为什么也不能直接初始化? // 这也是同样的道理,这里的VALUE属于对象,而对象要用使用时 // 才分配空间,而在这里是无法分配空间的。可以在构造函数的初始化列表中初始化
// const在类不同对象中可能值不一样,也就是说const在单个对象中是不可变的,但对于类是可变的
//3. static const int VALUE = 1;为什么这样的语句合法? // 当这两种的结合,其意义就跟一般的全局常量差不多,
//进入符号表并且初始化为1 static const int VALUE = 1; }; int main() { cout << "1 + 2 + 3 + ...+ 10 = " << Sum<10>::VALUE << endl;//VALUE的值在编译期就确定了,所有非常高效 cout << "1 + 2 + 3 + ...+ 100 = " << Sum<100>::VALUE << endl; return 0; }
用数组类模板来实现数组类:
//Array.h
#ifndef _ARRAY_H_ #define _ARRAY_H_ template <typename T, int N> class Array { protected: T a[N]; public: int length(); int length()const;//const对象时用,与上面的函数构造重载 bool get(int index, T& value); bool set(int index, T value); T& operator [] (int index); //返回引用可以做左值 virtual ~Array();//允许被继承,声明为虚函数 }; #endif template <typename T, int N> int Array<T, N>::length() { return N; } template <typename T, int N> int Array<T, N>::length()const { return N; } template <typename T, int N> bool Array<T, N>::set(int index, T value) { bool ret = (0 < index) && (index < length()); if(ret) { a[index] = value; } return ret; } template <typename T, int N> bool Array<T, N>::get(int index, T& value) { bool ret = (0 < index) && (index < length()); if(ret) { value = a[index]; } return ret; } template <typename T, int N> T& Array<T, N>::operator [] (int index) { return a[index]; } template <typename T, int N> Array<T, N>::~Array() { };
//HeapArray.h
#ifndef _HEAPArray_H_ #define _HEAPArray_H_ template < typename T > class HeapArray { private: T* m_poiter; int m_length; HeapArray(int length);//构造函数私有,不允许继承 HeapArray(const HeapArray<T>& obj); bool construct(); public: static HeapArray<T>* NewInstance(int length); int length(); int length()const;//const对象时用 bool get(int index, T& value); bool set(int index, T value); T& operator [] (int index); HeapArray<T>& self(); ~HeapArray(); }; template < typename T > HeapArray< T >::HeapArray(int length) { m_length = length; } template < typename T > bool HeapArray< T >::construct() { m_poiter = new T[m_length]; return m_poiter != NULL; } template < typename T > HeapArray< T >* HeapArray< T >::NewInstance(int length) { HeapArray< T >* ret = new HeapArray(length); if(!(ret && (ret->construct()))) { delete ret; ret = NULL; } return ret; } template < typename T > int HeapArray< T >::length() { return m_length; } template < typename T > int HeapArray< T >::length()const { return m_length; } template < typename T > bool HeapArray< T >::get(int index, T& value) { bool ret = (0 < index) && (index < length()); if(ret) { value = m_poiter[index]; } return ret; } template < typename T > bool HeapArray< T >::set(int index, T value) { bool ret = (0 < index) && (index < length()); if(ret) { m_poiter[index] = value; } return ret; } template < typename T > T& HeapArray< T >::operator [] (int index) { return m_poiter[index]; } template < typename T > HeapArray<T>& HeapArray< T >::self() { return *this; } template < typename T > HeapArray< T >::~HeapArray() { delete[] m_poiter; } #endif
//main.cpp
#include<iostream> #include"Array.h" #include"HeapArray.h" using namespace std; int main() { /********************************Array*********************************/ Array< double, 5 > a1; int length = a1.length(); cout << "a1.length() = " << a1.length() << endl; for(int i=0; i<a1.length(); i++) { a1[i] = i + 1; } for(int i=0; i<a1.length(); i++) { cout << a1[i] << endl; } const Array< int, 10 > a2; cout << "a1.length() = " << a2.length() << endl; cout << endl; /*****************************HeapArray*********************************/ HeapArray<int>* a3 = HeapArray< int > :: NewInstance(15); if(a3 != NULL) { HeapArray<int>& array = a3->self(); cout << "array.length() = " << array.length() << endl; for(int i=0; i<array.length(); i++) { array[i] = i + 1; } for(int i=0; i<array.length(); i++) { cout << array[i] << endl; } } delete a3;//记得要销毁对象 return 0; }
二、小结
(1)、模板参数可以是数值型参数
(2)、数值型参数必须在编译期唯一确定
(3)、数组类模板是基于数值型模板参数实现的
(4)、数组类模板是简易的线性表数据结构