C++ Templates (2.2 使用Stack類模板 Use of Class Template Stack )

返回完整目錄

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節中詳細討論。 ↩︎