一、前言 
模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。
模板是创建泛型类或函数的蓝图或公式。其是一种将数据类型作为参数的通用程序设计方法。允许开发人员编写可以处理各种数据类型的代码,而无需为每种数据类型编写不同的代码。库容器,比如迭代器和算法,都是泛型编程的例子,它们都使用了模板的概念。
每个容器都有一个单一的定义,比如 向量,我们可以定义许多不同类型的向量,比如 vector  或 vector 。  
二、模板的定义 
1. 函数模板 
模板函数定义的一般形式
1 2 3 4 template  <typename  type> ret-type func-name (parameter list){     } 
在这里,type 是函数所使用的数据类型的占位符名称。这个名称可以在函数定义中使用。相当于int、float等等。
模板是一种通用程序设计方法,它允许开发人员编写可以处理各种数据类型的代码。模板定义了一种通用的程序结构,该结构可以使用任何数据类型。例如,我们可以编写一个模板函数来交换任何两个变量,无论它们是整数、浮点数还是其他类型的数据。
一个简单的示例,交换输入的两个变量数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include  <iostream>  using  namespace  std;template  <typename  T1>void  Swap (T1& a, T1& b)     T1 t = a;     a = b;     b = t; } int  main ()     int  a = 2 ;     int  b = 3 ;     cout <<"a = "  << a << ";  b = "  << b <<endl;     Swap (a,b);     cout << "Swap: \n"  <<"a = "  << a << ";  b = "  << b <<endl;     float  c = 0.02 ;     float  d = 0.03 ;     cout <<"c = "  << c << ";  d = "  << d <<endl;     Swap (c,d);     cout << "Swap: \n"  <<"c = "  << c << ";  d = "  << d <<endl;     char  x = 'x' ;     char  y = 'y' ;     cout <<"x = "  << x << ";  y = "  << y <<endl;     Swap (x,y);     cout << "Swap: \n"  <<"x = "  << x << ";  y = "  << y <<endl;     return  0 ; } 
运行结果
1 2 3 4 5 6 7 8 9 a = 2;  b = 3 Swap: a = 3;  b = 2 c = 0.02;  d = 0.03 Swap: c = 0.03;  d = 0.02 x = x;  y = y Swap: x = y;  y = x 
下面也是函数模板的示例,返回两个数中的最大值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include  <iostream>  #include  <string>    using  namespace  std;  template  <typename  T>inline  T const & Max  (T const & a, T const & b)      return  a < b ? b:a;  }  int  main  ()       int  i = 39 ;     int  j = 20 ;     cout << "Max(i, j): "  << Max (i, j) << endl;        double  f1 = 13.5 ;      double  f2 = 20.7 ;      cout << "Max(f1, f2): "  << Max (f1, f2) << endl;        string s1 = "Hello" ;      string s2 = "World" ;      cout << "Max(s1, s2): "  << Max (s1, s2) << endl;        return  0 ; } 
运行结果
1 2 3 Max(i, j): 39 Max(f1, f2): 20.7 Max(s1, s2): World 
2. 类模板 
正如我们定义函数模板一样,我们也可以定义类模板。泛型类声明的一般形式如下所示:
1 2 3 4 5 6 template  <class  type > class  class -name { . . . } 
来看一个简单的类模板示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include  <iostream>  using  namespace  std;template  <typename  T>class  Pow {public :    T process (T v)        {        return  v * v;     } }; int  main ()     Pow<int > PowInt;     Pow<double > PowDouble;     cout << "5 * 5 = "  << PowInt.process (5 ) <<endl;     cout << "0.5 * 0.5 = "  << PowDouble.process (0.5 ) <<endl; } 
运行结果:
1 2 5 * 5 = 25 0.5 * 0.5 = 0.25 
在这个例子中,typename T表示类型参数。在创建一个Pow对象时,我们可以指定我们想要存储的数据类型。例如,我们可以创建一个Pow对象来操作整数,或者创建一个Pow对象来操作浮点数。  
下面的示例定义了类 Stack<>,并实现了泛型方法来对元素进行入栈出栈操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 #include  <iostream>  #include  <vector>  #include  <cstdlib>  #include  <string>  #include  <stdexcept>    using  namespace  std;  template  <class  T >class  Stack  {   private :      vector<T> elems;          public :      void  push (T const &)      void  pop ()      T top ()  const  ;                 bool  empty ()  const          return  elems.empty ();      }  };    template  <class  T >void  Stack<T>::push  (T const & elem) {           elems.push_back (elem);     }    template  <class  T >void  Stack<T>::pop  () {      if  (elems.empty ()) {          throw  out_of_range ("Stack<>::pop(): empty stack" );      }          elems.pop_back ();          }    template  <class  T >T Stack<T>::top  () const   {      if  (elems.empty ()) {          throw  out_of_range ("Stack<>::top(): empty stack" );      }          return  elems.back ();       }    int  main ()      try  {          Stack<int >         intStack;           Stack<string> stringStack;                        intStack.push (7 );          cout << intStack.top () <<endl;                     stringStack.push ("hello" );          cout << stringStack.top () << std::endl;          stringStack.pop ();          stringStack.pop ();      }      catch  (exception const & ex) {          cerr << "Exception: "  << ex.what () <<endl;          return  -1 ;     }  } 
运行结果:
1 2 3 7 hello Exception: Stack<>::pop(): empty stack 
三、tips 
1.  C++ 中 typename 和 class 的区别 
在 C++ Template 中很多地方都用到了 typename 与 class 这两个关键字,而且好像可以替换,是不是这两个关键字完全一样呢?
相信学习 C++ 的人对 class 这个关键字都非常明白,class 用于定义类,在模板引入 c++ 后,最初定义模板的方法为template<class T>......这里 class 关键字表明T是一个类型,后来为了避免 class 在这两个地方的使用可能给人带来混淆,所以引入了 typename 这个关键字,它的作用同 class 一样表明后面的符号为一个类型,这样在定义模板的时候就可以使用template<typename T> ......
typename 难道仅仅在模板定义中起作用吗?其实不是这样,typename 另外一个作用为:使用嵌套依赖类型(nested depended name),如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 class  MyArray  {      public :     typedef  int  LengthType; ..... } template <class  T>void  MyMethod ( T myarr )      typedef  typename  T::LengthType LengthType;      LengthType length = myarr.GetLength;  } 
这个时候 typename 的作用就是告诉 c++ 编译器,typename 后面的字符串为一个类型名称,而不是成员函数或者成员变量,这个时候如果前面没有 typename,编译器没有任何办法知道 T::LengthType 是一个类型还是一个成员名称(静态数据成员或者静态函数),所以编译不能够通过。
2. 函数模板可以重载,只要它们的形参表不同即可 
下面的两个模板可以同时存在
 1 2 3 4 5 6 7 8 9 10 template <class  T1, class  T2>void  print (T1 arg1, T2 arg2)   cout<<arg1<<" " <<arg2<<endl;  } template <class  T>void  print (T arg1, T arg2)   cout<< arg1<< " " << arg2<< endl; } 
参考链接 
C++模板和泛型编程详解 - 知乎 (zhihu.com) 
菜鸟教程-C++模板