程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 模板實例化,模板實例

模板實例化,模板實例

編輯:C++入門知識

模板實例化,模板實例


如果說上一篇博文《模板名稱》是教人怎麼寫模板,那麼這一篇就是教人怎麼使用模板。

模板實例化的復雜性在於:對於產生自模板的實體,它們的定義已經不再局限於源代碼中的單一位置。 一、理解兩個概念 (1)實例化:實例化在C++中通常指“根據類型創建一個對象”,但是在模板裡面,實例化是指使用具體值替換模板實參,從模板中產生普通類,函數或者成員函數過程。 (2)特化:這個過程最後獲得的試題就是我們所說的特化。 然而,實例化過程並不是特化的唯一方式,還有顯式特化,通過引入一個template<>來實現,如下: template<typename T1, typename T2> class MyClass{};   template<> class MyClass<std::string, float>{};   二、按需實例化(on-demand實例化) 如果(某個組件)期望知道模板特化的大小,或者訪問該特化的成員,那麼整個定義就需要位於作用域中。 比如顯示的調用模板的成員,或者是包含隱式轉換 (1)顯示調用成員函數 template<typename T> class C;   //前置聲明 C<int>* p = 0; //這裡只需要聲明就夠了   template<typename T> class C{     public:         void f(); };   void g(C<int>& c){     c.f();                    //此處需要知道整個模板的定義,因為編譯器要確定f()是不是可以被訪問到 }   (2)隱式類型轉換 C++重載規則要求:如果候選函數的參數是class類型,那麼該類型所對應的類就必須可見 template <typename T> class C{ public:     C(int);  //單參數隱式類型轉換 };   void candidate(C<double> const&); //①允許編譯器實例化該重載函數,但不是必須的,在VS2013中,就沒有實例化參數 void candidate(int){}                        //②   int main() {     candidate(42);         //編譯器不會選擇①處的聲明,因為一個精確的匹配要優於顯式轉型所獲得的匹配     return 0; }    三、延遲實例化 編譯器只對確實需要的部分實例化。換句話說,編譯器會延遲模板的實例化。 (1)當隱式實例化類模板時,同時也實例化了該模板的每一個成員函數的聲明,但並沒有實例化相應的定義。 但是有些情況是不會延遲的,如下: ①類模板裡面包含有匿名的union,那麼,匿名的union成員同時也被實例化, ②虛函數,作為實例化類模板的結果,許多編譯器實現都會實例化虛函數的定義,因為“實現虛函數調用機制的內部結構”要求虛函數的定義作為鏈接實體的存在。 (2)實例化類模板與實例化缺省的函數調用實參是分開的。換句話說,只有函數確實使用了缺省的實參,才會實例化該實參,如果這個函數不使用缺省的實參,那麼就不會實例化該缺省的實參,而是顯式使用實參來實例化。 template<typename T> class Safe{};   template<int N> class Danger{     typedef char Block[N];            //如果N<=0的話,將會出錯 };   template<typename T, int N> class Tricky{ public:
    virtual ~Tricky(){}    //虛函數,並提供了定義
    void no_body_here(Safe<T>=3);     //該缺省實參是可疑的,但沒有被使用,不會被實例化,不會出錯
    void inclass(){
        Danger<N>no_boom_yet;          //沒有被使用,不會被實例化,不會出錯 } //void error(){ Danger<0> boom;}      //如果沒有被注釋,會被要求給出這個類Danger<0>的完整定義,
//而實例化Danger<0>會出錯,即使沒有被使用,也不會被實例化,但仍然能夠引發一個錯誤
//該錯誤是在泛模板處理中產生的
//void unsafe(T(*p)[N]);        //如果 沒有注釋掉的話,此處實例化聲明的時候會出錯 T operator->(); //virtual Safe<T> suspect();     //虛函數,但是沒有提供定義,所以會引發一個鏈接期的錯誤, //如果不注釋掉的話,鏈接器就會給出這類錯誤 struct Nested{
    Danger<N> pfew;      //因為沒有使用該結構,所以此處的沒有實例化
};  

union{

 

    int align;

 

Safe<T> anonymous;

  }; };   int main() {     Tricky<int, 0> ok; } 三、C++實例化模型  (1)兩階段查找 第一階段:使用普通查找規則(在適當情況也會使用ADL)對模板進行解析,查找非依賴型名稱。另外非受限的依賴型名稱(諸如函數調用中的函數名稱,因為其具有一個依賴型實參)也會在這個階段查找,只不過查找不完全,在實例化模板的時候還會再次進行查找。   第二階段:發生在模板被實例化的時候,我們也稱此時發生的地點(或源代碼的某個位置)為一個實例化點POI。依賴型受限名稱就在此時查找。另外,非受限的依賴型名稱在此階段也會再次執行ADL查找.   (2)POI(實例化點) ①對於指向非類型(也就是函數╮( ̄▽ ̄")╭)特化的引用, C++把他的POI定義在“包含這個引用定義或聲明之後的最近名字空間域”。 class MyInt{     public:     MyInt(int i); };   MyInt operator - (MyInt const); bool operator >(MyInt const&, MyInt const&); typedef MyInt int;    //② template <typename T> void f(T i)    {     if(i>0){         g(-i);   //① } } //(1) void g(Int)    //這就是那個定義或聲明 { //(2)     f<Int>(42); //這就是那個引用 //(3) } //(4)這就是那個“之後最近的名字空間域”,函數f<int>的一個特化會出現在這裡   【注意】①位置的名稱g, 是非受限依賴型名稱,因為他的參數是依賴型的, 所以會在第二階段查找只是使用ADL就能夠找到函數g(Int)其實也就是g(MyInt);如果將MyInt替換成int,即②處為typedef int Int,那麼第二階段的查找關聯命名空間就會是空集,也就找不到函數g(Int)的聲明和定義。   ②對於產生自模板的類實例的引用,它的POI只能定義在“包含這個實例引用定義或聲明之前的最近名字空間域”。 template<typename T> class S{      public:         T m; }; //(5) 這裡就是S的POI unsigned long h() //這就是那個定義或聲明 {     //(6)     return (unsigned long) sizeof(S<int>);  //這就是那個實例引用     //(7) } //(8)    四、顯式實例化   為模板特化顯式的生成POI是可行的,我們把這種特化的構造成為顯式實例化指示符。從語法關鍵字上講,它有關鍵字template和後面的特化聲明組成,所聲明的特化就是即將有實例化獲得的特化。   template<typename T> void f(T) throw(T){}   下面有4個有效的顯式實例化實體 template void f<int>(int) throw(int); template void f<>(int) throw(int);  template void f(int) throw(int); //通過演繹獲得 template void f(int); //異常規范也可以省略,如果沒有省略,異常規范必須匹配相應的模板   C++規定: 同一個程序中,每一個特定的模板特化最多只能存在一處顯式實例化。而且,如果摸個模板特化已經被顯式實例化(使用template),那麼就不能對其進行顯式特殊化(使用template<>)。  

模板實例化

學編程 請上安全防線 百度第一
 

對於C++模板實例化中的錯誤

#include<iostream>
using namespace std;
template<class T> //這裡沒加這個模版
class stack
{
public:
stack(int MaxStackSize=10);
~stack(void){delete []element;}
bool IsEmpty()const {return top==-1;}
bool IsFull()const{return top==MaxTop;}
stack<T>& Add(const T &x);
stack<T>& Delete(T& x);
private:
int top;
int MaxTop;
T* element ;
};
class Position
{
public:
Position(void){};
~Position(void){};
int row,col;
};
template<class T>
stack<T>::stack(int MaxStackSize)
{
MaxTop=MaxStackSize-1;
element=new T[MaxStackSize];
top=-1;
}

template<class T>
stack<T>& stack<T>::Add(const T& x)
{
if(IsFull())
{
cout<<"棧滿"<<endl;
exit(1);
}
else
{
element[++top]=x; //這裡是element而不是stack
}
return *this;
}
template<class T>
stack<T>& stack<T>::Delete(T &x)
{
if(IsEmpty())
{
cout<<"棧空"<<endl;

}
else
{
x=element[top--];
}
return *this;

}
bool FindPath()
{
int **maze,m;
cout<<"請輸入矩陣的大小:"<<endl;
cin>>m;
stack<Position>*path;
path=new stack<Position>(m*m-1);
Position offset[4];
offset[0].row=0;offset[0].col =1;//向右
offset[1].row=1;offset[1].col =0;//向下
offset[2].row=0;offset[2].col =-1;//向左
offset[3].row=-1;offset[3].col =0;//向上
maze=new int *[m];
for(int i=0;i<m+2;i++)
{
cout<<"請輸入第"<<i+1<<"行元素:"<<endl;......余下全文>>
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved