STL学习小记--与C++模板相关的几个特性
先談談模板在我腦子里的典型吧
template<class T> const T& GetMax(const T& t1, const T& t2) {return t1>t2?t1:t2; }如上面的代碼,這是一個模板函數(template function)。要使用這個函數,傳入的參數必須滿足>運算符的條件。在C#中有where關鍵字,很可惜C++的模板沒有這種限制。
而據說BS本人也一再聲明C++的模板不需要這種限制,作為一個初學者,其中緣由就不得而知了。
template并非一次編譯便生成適合所有類型的代碼,而是針對被使用的某個(組)類型進行編譯。這導致一個很嚴肅的問題:實際處理template的時候,面對template function,必須先提供一個實際的例子,然后才能調用,這樣才能通過編譯。所以使用template function的話,需要將整個函數定義在頭文件中,在別處使用也需要提供源碼。C++標準中似乎有對于使template運行可移植性的方法(編譯成dll),但是貌似我使用的編譯器都不支持。
模板和宏在功能上相似,這類的問題經常引起大神們的口水戰,吾輩且避之。
下面登記下模板中使用的幾個特性:
1, Nontyoe Template?Parameters(非類型模板參數)
第一次遇到這個是在學習STL的bitset的時候。后來發現很多書在引入這內容的時候都是拿bitset舉例。
bitset<32> bs32;作為初學者的我,剛見到的時候非常疑惑,原來模板還有這種用法,可是這種方式來初始化構造的話,為什么不直接用構造函數呢?就像是建一個32長度的數組一樣的方式啊。
可是,32長度的數組不是一個類型,同樣,用構造函數創建的32長度容器也不是某一類型,而是某一類型的實例。而bitset<32>則是一個類型,檔次果然就不一樣了呀。
即是說,如果繼續聲明一個bitset<32> bs32X;那么bs32X和bs32的類型是一樣的,用RTTI來鑒別,typeid就是一樣的。這樣bs32和bs32X是允許相互賦值的。
而如果聲明一個bitset<33> bs33; 那就不是同一類型了。
嗯,模板類是在類級別,而一個是在實例級別,檔次呀檔次。。。
2,Default Template Parameters(缺省模板參數)
C++允許函數有缺省參數, 很方便地, 也允許模板參數有缺省值
比如下例:
template <class T, class NT= int> class P { public:T m_t;NT m_nt; };這樣在使用的時候,即使只是定義
void f() {P<int> p; //... }這樣也會被默認為P<int, int>的類型。很方便地特性,和函數缺省參數一樣,能減少不少代碼量。
3, typename
定義一個模板類或是模板函數的時候,需要制定類型的名字,使用T似乎已經是一種潛規則了。
而T前面可以使用typename,也可以使用class來表示后面的標識符是一個類型名。
而關鍵字typename還可以被用來作為類型前的標識符號。
比如:
template <class T> class P {typename T::MyType* pT; };如果不使用typename關鍵字,按照C++的一般規則,除了typename修飾之外的任何template中的標識符都被視為一個值而非一個類型,所以編譯器就會認為MyType是T中的一個成員,這一行被解釋為MyType和pT相乘。調用語句寫在類定義中編譯器就要報錯了。
使用上面的類模板,傳入的模板參數必須滿足類型中定義了MyType類型,可以使用typedef,可以直接定義class。
4, Member Template(成員模板函數)
全局函數可以是一個template, 同樣C++也允許類成員函數是一個template。但是這樣的成員函數不能使虛函數,而且也不能有缺省參數。(話外音:那不就是一個帶this指針參數的全局函數而已嗎?)
比如:
class A { public:template<class T>void f(T t){//... } };然后使用的時候只需要實例化一個A類型的變量就能對各種適用的類型使用f函數了。f函數的具體實現不影響A類型,相當方便。
另外需要提到的是,這個特性常常會被用來作為模板類之間類型轉換。
如同在第一個特性中提到的,根據模板參數的不同,類型也會不同,比如MyClass<int>和MyClass<double>屬于兩個不同的類型,那么兩者之間是不能直接轉換的,即使int可以轉換為double。為了滿足這種懶惰成性的需求,就可以使用這個特性。
如下代碼:
template <class T> class A { public:T m_value;A():m_value(){}A(const T& t){m_value = t;}template<class T2>void Parse(const A<T2>& t){this->m_value = t.m_value;} };int main() {A<int> a1(102);A<double> a2(12.222);A<char> a3('a');a1.Parse(a2);cout<<a1.m_value<<endl;//輸出12a2.Parse(a3);//字符'a'將轉化為ASCII碼cout<<a2.m_value<<endl;//輸出97system("pause"); }其實這里既然是int轉double,那么也可以做成直接用a1來初始化a2。也就是在a2的構造函數中使用a1作為參數。(話外: 構造函數也是成員函數,滿足非虛函數亦沒有缺省參數的條件)
template <class T> class A { public:T m_value;A():m_value(){}A(const T& t){m_value = t;}template<class T2>A(const A<T2>& t){m_value = t.m_value;} };int main() {A<int> a1(97);A<int> a2(a1);A<char> a3(a1);cout<<a1.m_value<<endl;//97cout<<a2.m_value<<endl;//97cout<<a3.m_value<<endl;//asystem("pause"); }這里a2構造的時候調用的是默認的拷貝構造函數,而a3構造的時候使用的是模板拷貝構造函數。
5, Nested Template(嵌套模板類)
?類中定義的函數可以是模板函數,類中定義的嵌套類也可以是個模板類。
template <class T> class MyClass {//... public:template <class T2>class NestedClass{//... }; };另外的注意點
面試題是個很有意思的東西,往往能遇到許多稀奇古怪的狀況。以前曾在面試中遇到這樣的問題:
int* pI = new int;
int* pI2 = new int();
上面兩行代碼有什么區別。
我大學匯編是玩NDS上課的,所以無法從那個方向去分析。只是根據實際使用來猜想, 前者分配了空間卻沒有初始化值,后者分配了空間并初始化值。
這和下面的情況相似(貌似使用自定義類型的時候不一定了):
int i; //undefined value
int i2 = int(); ?//initialized with zero
這是基本類型int,那么自定義類型呢?
自定義的class有時候不會顯式地定義一個構造函數。
struct XX {//XX():n(){}int n; };int main() {XX* pX1 = new XX;XX* pX2 = new XX();cout<<pX1->n<<", "<<pX2->n<<endl; }輸出的結果是一個未初始化的值和0
那如果自定義的類型已經有一個無參構造函數了呢?那就會調用這個無參構造函數來初始化了。
所以,以后一定要養成定義一個無參構造函數并初始化成員的好習慣啊%>_<%
那么,使用模板的時候呢,使用這個語法可以保證該類型實例能被初始化為一個確切的初值。
摘自:ISO/IEC 14882:2003(E) 5.3.4 - 15
— If the new-initializer is omitted:
??????— If T is a (possibly cv-qualified) non-POD class type (or array thereof), the object is default-initialized(8.5). If T is a const-qualified type, the underlying class type shall have a user-declared default constructor.
??????— Otherwise, the object created has indeterminate value. If T is a const-qualified type, or a (possibly cv-qualified) POD class type (or array thereof) containing (directly or indirectly) a member of const-qualified type, the program is ill-formed;
— If the new-initializer is of the form (), the item is value-initialized (8.5);
?
?
?
轉載于:https://www.cnblogs.com/pasoraku/archive/2013/04/12/3016782.html
總結
以上是生活随笔為你收集整理的STL学习小记--与C++模板相关的几个特性的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux中select()函数分析
- 下一篇: s3c2440移植MQTT