C++ Templates (2.2 使用Stack類别範本 Use of Class Template Stack )

失落孤舟發表於2020-09-01

返回完整目錄

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,int作為類别範本內T的型別。因此,intStack為一個使用vector為元素的物件,任何被呼叫的成員函式將相應地例項化。相似地,通過宣告Stackstd::string,建立一個使用vectorstd::string為元素的物件,任何被呼叫的成員函式將相應地例項化。

注意,只有被呼叫的模板(成員)函式程式碼才能被例項化。對於類别範本,成員函式只有被呼叫才會例項化。這節省了時間和空間,同時也使得類别範本可以被部分使用,這將在第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節)。

腳註


  1. C++17引入了類别範本實參推斷,這使得可以跳過指定模板實參,只要可以從建構函式推斷出模板實參。這將在2.9節中詳細討論。 ↩︎

相關文章