1.判断下面完全泛化推演的类型是什么?
template<class T> void fun(T a) { T x,y; cout << typeid(T).name() << endl; cout << typeid(a).name() << endl; } int main() { int x = 10; const int y = 20; int* xp = &x; const int* yp = &y; fun(x);//T:int a:int fun(y);//T:int a:int fun(&x);//T:int* a:int* fun(&y);//T:const int* a:const int* fun(xp);//T:int* a:int* fun(yp);//T:const int* a:const int* fun(&xp);//T:int** a:int** fun(&yp);//T:const int** a:const int** return 0; }
注意:完全泛化中,T和a的类型是一样的
2.判断下面部分特化推演的类型是什么?
template<class T> void fun(T* a)//部分特化 { T x = 0,y = 0; cout << typeid(T).name() << endl; cout << typeid(a).name() << endl; } int main() { int x = 10; const int y = 20; int* xp = &x; const int* yp = &y; void* p = &x; fun(&x);//T:int a:int* fun(&y);//T:const int a:const int* fun(p);//error }
注意:部分特化中,T和a不一样,因为void fun(T* a)本身已经给出 * 了,所以a会比T多出一个 *
T x = 0,y = 0;会编译失败,推演之后会变成void* x = 0,y = 0;void* 不能定义类型,所以void* p = &x; fun§;会编译错误,如果把T x = 0,y = 0;去掉,是可以编译通过的
3.判断下面部分特化推演的类型是什么?
template<class T> void fun(const T* a)//部分特化 { T x = 0,y = 0; cout << typeid(T).name() << endl; cout << typeid(a).name() << endl; } int main() { const int y = 20; fun(&y);//T:int a:const int* return 0; }
注意:完全特化中,void fun(const T* a)已经给出了const和 * ,所以a会比T多出一个cosnt 和 *
4.判断下面引用形式推演的类型是什么?
template<class T> void fun(T &a)//引用 { T x,y; cout << typeid(T).name() << endl; cout << typeid(a).name() << endl; } int main() { int x = 10; const int y = 20; int* xp = &x; const int* yp = &y; fun(x);//T:int a:int& fun(y);//T:const int a:const int& fun(xp);//T:int * a:int *& fun(yp);//T:const int* a:const int*& //fun(&x);//&x:x的地址是一个常量,所以要对引用有const修饰,即int* const &p = &x;但是编译器不能推演出这样,编译器只能在int 和 * 中间推演出const,不能在int* 之外推演出const,所以不能编译通过,如果想让他编译通过,就在void fun(T& a)中加上void fun(T const &a) //fun(&y);//T:const int* a:const int*& return 0; }
注意:是可以引用一个指针的
5.模板函数的重载
template<class T> void fun(T a,int) {} void fun(T a,char) {} int main() { fun(12,23);//调用第一个函数 fun(12,'a');//调用第二个函数 return 0; }
6.类模板和函数模板不同,类模板不存在推演的过程,必须要给出类型Stack st;
template<class T> class Stack { private: T* data; size_t count; public: void Push(const T& x); }; int main() { Stack<int> st; }
注意:不是进行替换(即不是用int替换T),而是代码的生成,会编译成下面的程序
class Stack<int> { typedef int T;//using T = int 两者是等价的,这是c11的标准 private: T* data; size_t count; public: void Push(const T& x); };
7.下面程序is和ist的类型一样吗?
template<class T,int N> class Stack { private: T data[N]; public: void push(const T& x) }; int main() { Stack<int,100> is; Stack<int,10> ist; return 0; }
答案:不一样。会在编译时分别生成如下的代码
class Stack<int,100> { typedef int T; private: T data[100]; public: void push(const T& x) }; class Stack<int,10> { typedef int T; private: T data[10]; public: void push(const T& x) };
template<class T,int N>中T是类型,N是非类型,N在编译的时候就进行了替换,可以理解为是宏替换
如果类模板中的成员函数没有被调用,那么该成员函数不会被实例化,只有在调用时,才会进行实例化
注意:对于模板来说,模板类和模板的成员函数都包含在一个头文件中,现有的编译器无法做到这一点,即在头文件中进行模板的设计,在.cpp文件中引入头文件,然后实现成员函数,因为依赖关系太复杂了,没有人能做到,所以现有的编译器都不能做到这一点
8.类模板默认值
template<class T = int,int N = 100> class Stack { private: T data[N]; public: void push(const T& x) { cout << N << endl; N = 100; } }; int main() { Stack st;//编译器可能会编译通过,也可能不会编译通过,最好不用这种方法 Stack<> st;//yes。告诉编译器是一个是一个模板类型 Stack<int,10> ist;//yes Stack<int> ist2;//yes Stack<,1000> ist3;//error,默认值传参数的时候是从左向右传,不能跳过 }
设置默认值的时候是从右向左,不能跳过,传递参数的时候从左向右传递,也不能跳过
9.多模板参数类型
template<class T,class U,class R> class Queue {}; 当类型更多时,可以用下面的方法 template<class...Arg>//c11标准 class Queue {}; 这个叫多模板参数类型
10.模板类型里面可以是类型也可以是非类型
11.对于自定义类型,最好不要用new来开辟连续的空间
template<class T> class Array { private: enum{ INIT = 10 }; T* data; size_t capacity;//容量 size_t count;//元素个数 public: Array() { count = 0; data = new T[capacity = INIT]; } ~Array() {delete[] data;} }; class String { private: char* str; public: String(const char*p = NULL) {} }; int main() { Array<String> sar; }
这时T就是String类型,new不仅要开辟10个格子的空间,而且还要调用构造函数来实例化对象,但是此时sar.count值为0,这就造成了逻辑上和物理上的冲突,所以对于自定义类型来说,不要使用new来开辟连续的空间,对于内置类型来说,是可以的
12.T是一个模板类型,什么类型都可以,Seq必须是一个模板类型
template<class T,template<class> class Seq> int main() { Container<int,int> iic;//是错误的,第二个int不是模板类型 Container<int,Array> container;//是正确的,Array是一个模板类型 Container<int,Array<int>> container;//是错误的,指明了Array是一个具体类型,处理int类型,就不能编译通过了 }
13.此时Array iar不是模板类型,因为编译器在编译时,它看到int时,会生成代码第二个程序代码,他已经进行实例化了,实例化成Array数组类型来处理整型
template<class T> class Array { private: enum{ INIT = 10 }; T* data; size_t capacity;//容量 size_t count;//元素个数 public: }; int main() { Array<int> iar; } class Array<int> { typedef int T; private: enum{ INIT = 10 }; T* data; size_t capacity;//容量 size_t count;//元素个数 }
当定义Array ;时它是一个模板类型,因为没有加<>,没有表明他是一个什么类型,就算模板有默认值类型template那么它依然是一个模板类型