模板 (C++)

模板（Template）指C++程式設計語言中的函式模板與類模板，是一種參數化類型機制，大體對應於java和C＃中的泛型，但也有一些功能上的顯著差異（C++模板支援後兩者沒有明確對應的模板模板參數和模板非類型參數，但不支援Java的萬用字元以及C#的泛型類型約束）。模板是C++的泛型編程中不可缺少的一部分。
模板是C++程式設計師絕佳的武器，特別是結合了多重繼承與運算子過載之後。C++的標準函式庫提供的許多有用的函式大多結合了模板的概念，如STL以及iostream。

模板的聲明與定義

模板定義以關鍵字template開始，後接模板形參表（template parameter list），模板形參表是用尖括號括住的一個或者多個模板形參的列表，形參之間以逗號分隔。模板形參可以是表示類型的類型形參（type parameter），也可以是表示常數運算式的非類型形參（non-type parameter）。非類型形參跟在類型說明符之後聲明。類型形參跟在關鍵字class或typename之後聲明。模板形參可以給出預設值（default arguments for template parameters）。

模板的模板參數

類別範本的模板參數允許是另外一個類別範本，這稱為模板的模板參數（template template parameter），也譯作「模板參數模板」。函式模板不允許有模板的模板參數。例如：
template<template <class T> class X> class A { }; //类模板A的第二个参数是另外一个类模板X
template<class T> class B { };
A<B> a; //模板A的实际使用。其中的B是模板的模板实参（template template argument）

模板參數的預設值

模板形參可以給出預設值（default arguments for template parameters）。如果一個模板參數給出了預設值，那麼模板形參列表中在其後聲明的模板參數都應該給出預設值。例如：
template<class T = char, class U, class V = int> class X { }; //编译出错，或者给出U的默认值，或者不给出T的默认值
一個模板的各次聲明給出的模板參數的預設值可以累積其效果。例如：
template<class T, class U = int> class A;
template<class T = float, class U> class A;
template<class T, class U> class A {
  public:
     T x;
     U y;
};
A<> a; //a.x is float, and the type of a.y is int
但是如果交換本範例第一行與第二行的次序，將編譯報錯。因為如果第一個模板參數T有了預設值，此時編譯器必須已經知道其後的第二個模板參數U的預設值。
在同一個作用域（scope）中，不能對同一個模板的同一個參數多次聲明其預設值。例如：
template<class T = char> class X;
template<class T = char> class X { };//编译报错。如果在本行中不给出模板参数T的默认值将编译通过
模板參數的作用域為從其聲明之處至該模板的定義結束之處。因此可以使用一個模板參數作為其後聲明的其他模板參數的一部分或預設值。例如：
template<class V, V obj> class C; 
template<class T, class U = T> class D { };

變數模板

變數模板（variable template）是C++14引入的新的一個種類的模板。可用於在命名空間作用域聲明一個變數。例如：
template<class T>
constexpr T pi = T(3.1415926535897932385);  // variable template
template<class T>
T circular_area(T r) // function template
{
   return pi<T> * r * r; // pi<T> is a variable template instantiation
}
可以在類作用域聲明一個靜態成員變數： 
struct matrix_constants
{
   template<class T>
   using pauli = hermitian_matrix<T, 2>; // alias template
   template<class T> static constexpr pauli<T> sigma1 = { { 0, 1 }, { 1, 0 } }; // static data member template
   template<class T> static constexpr pauli<T> sigma2 = { { 0, -1i }, { 1i, 0 } };
   template<class T> static constexpr pauli<T> sigma3 = { { 1, 0 }, { 0, -1 } };
};
類的靜態成員變數模板，也可以用類別範本的非模板成員變數來實現：
struct limits {
   template<typename T>
   static const T min; // declaration of a static data member template
};
template<typename T> const T limits::min = { }; // definition of a static data member template
template<class T> class X {
    static T s; // declaration of a non-template static data member of a class template
};
template<class T> T X<T>::s = 0; // definition of a non-template data member of a class template

變數模板不能用作模板的模板參數（template template arguments）。

模板的使用

使用模板時，可以在模板名字後面顯式給出用尖括號括住的模板實參列表（template argument list）。對模板函式或類的模板成員函式，也可不顯式給出模板實參，而是由編譯器根據函式呼叫的上下文推匯出模板實參，這稱為模板參數推導。
如果模板參數使用其預設值，則在模板實參列表中可以忽略它。如果所有的模板參數都使用了預設值，模板實參列表為空，但仍然必須寫出成對的尖括號。例如：
template<class T = int> class X { };
X<> a; //编译通过
X b;   //编译报错
對於作為類型的模板實參，不允許是局部類型（local type）、無連結性的類型（type with no linkage）、無名類型（unnamed type）或包括了這三種情形的複合類型。但C++11以及允許本地類型作為模板實參。

函式模板

以下以取最大值的函式模板maximum為例。此函式在編譯時會自動產生對應參數類型的代碼，而不用顯式聲明。
#include <iostream>template <typename T>inline const T& maximum(const T& x,const T& y){
   if(y > x){
      return y;
   }
   else{
      return x;
   }}int main(void){
   using namespace std;
   int a=3,b=7;
   float x=3.0,y=7.0;
   //Calling template function
   std::cout << maximum<int>(a,b) << std::endl;         //输出 7
   std::cout << maximum(a, b) << std::endl;             //自动补充类型声明
   std::cout << maximum<double>(x,y) << std::endl;  //输出 7
   return 0;}

模板的巢狀：成員模板

對於類中的模板成員函式、巢狀的成員類別範本，可以在封閉類的內部或外部定義它們。當模板成員函式、巢狀類別範本在其封閉類的外部定義時，必須以封閉類別範本的模板參數（如果它們也是模板類）和成員模板的模板參數開頭。如下例：
template <typename C> class myc{
  public:
    template <typename S> C foo(S s);};//下行需要给出外部类与内部嵌套类的模板形参列表：template<typename C> template <typename S> C myc<C>::foo(S s){C var;return var;   
}int main(){float f;myc<int> v1;v1.foo(f);}
C++標準規定：如果外圍的類別範本沒有特例化，裡面的成員模板就不能特例化。例如：
template <class T1> class A {
  template<class T2> class B {
      template<class T3> void mf1(T3);
      void mf2();
  };};template <> template <class X>
   class A<int>::B {
      template <class T> void mf1(T);
   };template <> template <> template<class T>
    void A<int>::B<double>::mf1(T t) { }template <class Y> template <>
     void A<Y>::B<double>::mf2() { } // ill-formed; B<double> is specialized but its enclosing class template A is not

別名模板

別名模板（aliase template）是C++11引入的技術。在C++03標準中，可以用typedef給全特化模板定義新的類型名。但是不允許用typedef施加於偏特化模板上。例如： 
template <typename First, typename Second, int Third>class SomeType;template <typename Second>typedef SomeType<OtherType, Second, 5> TypedefName; // Illegal in C++03
C++11增加了給偏特化模板增加別名的功能，例如： 
template <typename First, typename Second, int Third>class SomeType;template <typename Second>using TypedefName = SomeType<OtherType, Second, 5>;
using在C++11中也可用於其他的類型別名的聲明:
typedef void (*FunctionType)(double);       // Old styleusing FunctionType1 = void (*)(double); // New introduced syntax