[c++ primer plus]c++ 函數模版,類模版,實例化,具體化,模版作參數,模版的友元

模版不是類或函數,它們是c++編譯器指令,它只是一個用於生成類或函數的方案,說明如何生成類或函數。 具體生成時,稱爲實例化(instantiation)或具體化(specialization)。因此,模版不能單獨編譯,必須與特定的實例化請求一起使用。最簡單的辦法就是將所有模版信息放入一個頭文件裏,使用時include這個頭文件。如果編譯器支持export關鍵詞,則可以將“類模版”的聲明與定義分開存放在.h和.cpp中。

1. 函數模版的重載(利用可以重載的特徵標)

template <class Any>
void Swap(Any& a, Any& b);

//override
template <class Any>
void Swap(Any* a, Any* b, int n);

template 
<class Any>
void Swap(Any& a, Any& b)
{
    Any temp; temp 
= a; a = b; b = temp;
}


template 
<class Any>
void Swap(Any* a, Any* b, int n)
{
    Any temp;
    
for (int i = 0; i < n; i++)
    
{ temp = a[i]; a[i] = b[i]; b[i] = temp; }
}
main( )
{
    int i, j;
    double k[10], m[10];
    Swap(i, j);         //顯示實例化爲Swap<int>(int&, int&);
    Swap(k, m, 10);    //顯示實例化爲Swap<double>(double*, double*, int);
}

 2. 函數模版的顯式實例化,即可以命令編譯器直接創建 template<class Any> 的實例,把 class Any 實例化。

//explicit instantiation
template void Swap<int>(int&int&);
template 
void Swap<Cjob>(Cjob&, Cjob&);

3. 函數模版的顯式具體化,它不使用模版來生成函數定義,而應使用獨立的、專門的函數定義。顯式具體化要有自己的函數定義,而顯式實例化則不需要,這是兩者本質的區別。兩者的相同之處是:都生成了一個具體的函數,而不再是模板。

// explicit specialization,這兩種格式顯式實例化的格式等價,只需要一種就可以。
template <> void Swap<Cjob>(Cjob& a, Cjob& b);
template 
<> void Swap(Cjob&a, Cjob&
 b);

template 
<> void Swap<Cjob>(Cjob& a, Cjob& b)
{
    
string tStr;
    tStr   
= a.name;
    a.name 
= b.name;
    b.name 
= tStr;
}


template 
<> void Swap(Cjob& a, Cjob& b)
{
    
string tStr;
    tStr   
= a.name;
    a.name 
= b.name;
    b.name 
= tStr;
}

4. 函數模版的部分具體化,部分具體化與顯式具體化的區別在於:前者還是一個函數模板,而後者則已經是一個函數。前者的函數定義中,必然還有typename類型待定,這個類型將在函數模板被調用的時候得到“隱式”的具體化。

template <class T1, class T2, class T3>
void Swap(T1& a, T2& b, T3& c);

//explicit specialization
template <class T1, class T2> void Swap<T1, T2, int>(T1& a, T2& b, int& c);

//部分具體化,可以引入各種限制
template <class T1, class T2> void Swap<T1,T2, T2>(T1& a, T2& b, T2& c);
tempate 
<class T1> void Swap<T1, T1*, T1*>(T1& a, T1* &b, T1* &c);

template 
<class T1, class T2, class T3>
void Swap(T1& a, T2& b, T3& c)
{
..............
}


template 
<class T1, class T2> void Swap<T1, T2, int>(T1& a, T2&b, int& c)
{
..............
}

template <class T1, class T2> void Swap<T1,T2, T2>(T1& a, T2& b, T2& c);
{
.............
}

template 
<class T1> void Swap<T1, T1*, T1*>(T1 &a, T1* &b, T1* &c)
{
..............
}

5. 類模版之內與之外:在之內聲明時可以忽略類型,之外必須Stack<Type>帶上類型。

template <class Type>
class Stack
{
public:
    Stack
& operator= (const Stack& st);
}


template 
<class Type>
Stack
<Type> & Stack<Type> :: operator=(const Stack<Type>& st)
{
}
main ( )
{
    Stack<string> st;    //隱式的實例化
}

6. 類模版的默認類型參數,不能爲函數模版提供默認的類型參數。

template <class T1, class T2 = int> 
class Topo 
{
........
}
;
Topo<double, double> m1;
Topo<double> m2;    //使用默認類型

7a. 類模板的顯式實例化

template <typename T>
class SortedArray
{
public:
    T val
}
;

template 
class SortedArray<int>;

main ( )
{
    SortedArray
<int> sa;  //模板類與模板函數的區別在於:前者被調用時,總是要帶有<parameter-type>,而後者則不帶。因爲後者可以從形式參數來實例化或具體化模板;而前者則只能靠這個後綴,由編譯器決定生成哪種類型。(即使已經顯式實例化了,也要帶上後綴。)
}

7b. 類模板的顯式具體化

template <class T>
class SortedArray
{
 ........
}
;

//顯式具體化,定義新的類功能。
template <> class SortedArray<specialized-type-name> 
{
 ........
}
;
main ( )
{
    SortedArray<specialized-type-name> sa;
}

7c. 類模版的部分具體化

template <class T1, class T2, class T3>
class SortedArray
{
public:
    SortedArray() 
    
{
        printf(
"1 ");
    }


    T1 val1;
    T2 val2;
    T3 val3;
}
;

template 
<class T1, class T2> 
class SortedArray<T1, T2, T2>
{
public:
    SortedArray()
    
{
        printf(
"2 ");
    }


    T1 val1;
    T2 val2;
}
;

template 
<class T1> 
class SortedArray<T1, T1, T1>
{
public:
    SortedArray()
    
{
        printf(
"3 ");
    }


    T1 val;
}
;

template 
<> 
class SortedArray<intintint>
{
public:
    SortedArray()
    
{
        printf(
"4 ");
    }

}
;

int main(int argc, char* argv[])
{
    SortedArray
<intintint> sa1;
    SortedArray
<intint> sa2;
    SortedArray
<int> sa3;
    
//SortedArray sa4;

    printf(
"Hello World! ");
    
return 0;
}

8. 模版作爲模版類的成員

template <typename T>
class beta
{
private:
    template 
<typename V>
    
class hold;
    hold
<T> q;
    hold
<int> n;
public:
    template
<typename U>
    U blab(U u, T t);
}
;

//member define
template <typename T>
template 
<typename V>
class beta<T>::hold
{
private:
    V val;
public:
    V Value() 
const {return val;}
}
;

template 
<typename T>
template 
<typename U>
U beta
<T>::blab(U u, T t)
{
    ........
}
;

9. 模版作爲模版的參數,vc++不支持這種使用,g++支持。

template <typename V>
class Stack
{
....
}
;

template 
<template <typename T> class Thing>
class Crab
{
....
}
;

main()
{
    Crab
<Stack> vStack;
}

10. 模版類的非模版友元函數

template <typename T>
class HasFriend
{
    
public:
        HasFriend(
const T& i) : item(i) { ct++; }
        
~HasFriend() { ct--; }
        friend 
void counts();
        friend 
void report(HasFriend<T> &);
    
private:
        T item;
        
static int ct;
}
;

void counts()
{
// 每個類有獨立的static變量,模版沒有static變量,因爲模版只是提供給編譯器的方案,本身並不是類。只有模版實例化或具體化之後,纔可以訪問其static變量。
    cout << "HasFriend<int>: " << HasFriend<int>::ct;  
    cout 
<< "HasFriend<double>:" << HasFriend<double>::ct; 
}


// 必須爲每個類提供相應的友元。
void report(HasFriend<int> & hf)
{
    cout 
<< hf.itme;
}


void report(HasFriend<double> & hf)
{
    cout 
<< hf.item;
}


main()
{
    HasFriend
<int> hf1;
    counts();
    HasFriend
<double> hf2;
    counts();
    report(hf2);    
}

10. 模版類的約束模版友元。

//首先在類定義前面聲明-函數是模版函數
template <typename T> void counts();
template 
<typename T> void report(T&);

template 
<typename TT>
class HasFriendT
{
public:
    HasFriendT(
const TT& i) : item(i) { ct++; }
    
~HasFriendT() { ct--; }
//在類裏再次聲明爲友元,這裏也是某種程度上的實例化,
//但還沒有徹底實例化,函數還是模版。
    friend void counts<TT> ();
    friend 
void reports<HasFriendT<TT> > (HasFriendT<TT>&);
//這裏也可以寫做:
//friend void reports<> (HasFriendT<TT>&);
//讓編譯器自己判斷模版的參數類型!
private:
    TT item;
    
static int ct;
}
;

template 
<typename T>
int HasFriendT<T>::ct = 0;

template 
<typename T>
void counts()
{
//這裏並不是要輸出模版的大小、模版的static成員變量。因爲程序運行時,並不存在模版的實體,
//都是實例化後的確確實實存在的類。因此,這裏指的實例化的類。
    cout << "template size: " << sizeof(HasFriendT<T><< "";
    cout 
<< "template counts(): " << HasFriendT<T>::ct << endl;
}


template 
<typename T>
void report(T& hf)
{
    cout 
<< hf.item << endl;
}


int main()
{
    counts
<int>(); //隱式實例化counts,由模版函數變爲具體的函數

    HasFriendT
<int> hfi1(10); //隱式實例化類,並定義該實例化類的一個對象
    HasFriendT<int> hfi2(20); 
    HasFriendT
<double> hfdb(10.5);

    report(hfi1); 
//通過調用,隱式實例化函數
    report(hfi2);
    report(hfdb);

    
return 1;
}

 11. 模版類的非約束模版友元。

template <typename T>
class ManyFriend
{
public:
    ManyFriend(
const T& i) : item(i) {}
    template 
<typename C, typename D> friend void show2(C&, D&);
private:
    T item;
}
;

template 
<typename C, typename D>
void show2(C& c, D& d)
{
    cout 
<< c.item << "" << d.item << endl;
}


int main()
{
    ManyFriend
<int> hfi1(10);
    ManyFriend
<int> hfi2(20);
    ManyFriend
<double> hfdb(10.5);
    cout 
<< "hfi1, hfi2: ";
    show2(hfi1, hfi2);
    cout 
<< "hfdb, hfi2: ";
    show2(hfdb, hfi2);
    
return 0;
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章