C++ Templates (2.2 使用Stack類模板 Use of Class Template Stack )
- 2020 年 9 月 1 日
- 筆記
- C++, C++ Templates
2.2 使用Stack類模板 Use of Class Template Stack
在C++17以前,使用類模板必須顯式指定模板實參[1]。以下例子展示如何使用類模板Stack<>
// basics/stack1test.cpp
#include "stack1.hpp"
#include <iostream>
#include <string>
int main()
{
Stack<int> intStack; //int類型的棧
Stack<std::string> stringStack; //string類型的棧
//操作int類型的棧
intStack.push(7);
std::cout << intStack.top() << '\n';
//操作string類型的棧
stdString.push("hello");
std::cout << stringStack.top() << '\n';
stringStack.pop();
}
通過聲明類型Stack
注意,只有被調用的模板(成員)函數程式碼才能被實例化。對於類模板,成員函數只有被調用才會實例化。這節省了時間和空間,同時也使得類模板可以被部分使用,這將在第2.3節中討論。
本例中,int類型和string類型的默認構造函數、push()
函數、top()
函數都將被實例化,然而pop()
函數只有string類型的進行了實例化。如果類模板有靜態成員,這些靜態成員也只實例化一次,而且只有使用了類模板的那一種類型進行了實例化。
實例化後的類模板類型可以像其他類型一樣使用,可以用const或者volatile進行限定,或者基於它衍生出數組和引用。也可以將其作為typedef或者using進行類型定義的一部分(更多類型定義的內容詳見第2.8節),或者當構建其他模板類型時作為類型參數,比如:
void foo(Stack<int> const& s) //參數s是int的Stack
{
using IntStack = Stack<int>; //IntStack是Stack<int>的別名
Stack<int> istack[10]; //istack是長度為10的Stack<int>的數組
IntStack istack2[10]; //istack2也是長度為10的Stack<int>的數組
}
模板實參可以是任何類型,比如float類型的指針,甚至是int的Stack:
Stack<float*> floatPtrStack; //float指針的Stack
Stack<Stack<int>> intStackStack; //int的Stack的Stack
唯一的要求便是任何被調用的操作對於該類型是可行的。
注意到,C++11之前必須在兩個閉模板括弧(closing template brackets)之間放置空格:
Stack<Stack<int> > intStackStack; //任何C++版本都沒問題
如果不這麼做而使用符號 >>,這將導致語法錯誤:
Stack<Stack<int>> intStackStack; //C++11之前將引發錯誤
舊版本的這種行為的原因是這可以幫助C++編譯器在第一輪中將源程式碼分成獨立語義的片段(tokenize the source code independent of the semantics of the code)。然而,由於缺失空格是個典型的bug,這需要對應的錯誤消息,該程式碼的語義將越來越難以考慮在內。因此C++11移除了「在兩個閉合模板括弧中間必須加入空格」的規則,史稱「角括弧hack」(詳見13.3.1節)。
腳註
-
C++17引入了類模板實參推斷,這使得可以跳過指定模板實參,只要可以從構造函數推斷出模板實參。這將在2.9節中詳細討論。 ↩︎