1. 程式人生 > >c++11-17 模板核心知識(十二)—— 模板的模板引數 Template Template Parameters

c++11-17 模板核心知識(十二)—— 模板的模板引數 Template Template Parameters

- [概念](#概念) - [舉例](#舉例) - [模板的模板引數的引數匹配 Template Template Argument Matching](#模板的模板引數的引數匹配--template-template-argument-matching) - [解決辦法一](#解決辦法一) - [解決辦法二](#解決辦法二) ## 概念 一個模板的引數是模板型別。 ## 舉例 在[c++11-17 模板核心知識(二)—— 類模板](https://github.com/zhangyachen/zhangyachen.github.io/issues/152) 中,如果我們想要允許指定儲存Stack元素的容器,是這麼做的: ```c++ template > class Stack { private: Cont elems; // elements ...... }; ``` 使用: ```c++ Stack> dblStack; ``` 但是這樣的缺點是需要指定元素型別兩次,然而這兩個型別是一樣的。 使用模板的模板引數(Template Template Parameters),允許我們在宣告Stack類模板的時候只指定容器的型別而不去指定容器中 元素的型別。例如: ```c++ template class Cont = std::deque> class Stack { private: Cont elems; // elements public: void push(T const &); // push element void pop(); // pop element T const &top() const; // return top element bool empty() const { // return whether the stack is empty return elems.empty(); } ... }; ``` 使用: ```c++ Stack vStack; // integer stack that uses a vector ``` 與第一種方式的區別是:第二個模板引數是一個類模板: ```c++ template class Cont ``` 預設值從`std::deque`改為了`std::deque`. 在C++17之後,模板的模板引數中的class也可以使用typename,但是不可以使用struct和union: ```c++ template typename Cont = std::deque> class Stack { // ERROR before C++17 ... }; ...... template class C> // OK void f(C* p); template struct C> // ERROR: struct not valid here void f(C* p); template union C> // ERROR: union not valid here void f(C* p); ``` 當然,由於模板的模板引數中的Elem沒有用到,可以省略: ```c++ template class Cont = std::deque> class Stack { ... }; ``` **另外注意一點,模板的模板引數中的模板引數,只能和模板的模板引數配合用。有點饒,舉個例子:** ```c++ template class Buf> // OK class Lexer { static T* storage; // ERROR: a template template parameter cannot be used here ... }; ``` ## 模板的模板引數的引數匹配 Template Template Argument Matching 大家可以嘗試自己編譯一下上面的程式碼,可能會出現下列問題: ```c++ error: template template argument has different template parameters than its corresponding template template parameter template class Cont = std::deque> ... /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/deque:1197:1: note: too many template parameters in template template argument template */> ``` 意思是`std::deque`和`Cont`不匹配。標準庫的`std::deque`有兩個引數,還有一個預設引數Allocator : ```c++ template > class _LIBCPP_TEMPLATE_VIS deque; ``` ### 解決辦法一 將Cont和std::deque的引數匹配即可: ```c++ template > class Cont = std::deque> class Stack { ...... }; ``` 這裡的Alloc沒有用到,同樣可以省略。 成員函式定義舉例: ```c++ template class Cont> void Stack::push (T const& elem) { elems.push_back(elem); // append copy of passed elem } ``` ### 解決辦法二 利用[c++11-17 模板核心知識(四)—— 可變引數模板 Variadic Template](https://github.com/zhangyachen/zhangyachen.github.io/issues/154) ```c++ template class Cont = std::deque> class Stack { ...... }; ``` 但是,這點對於`std::array`無效,因為std::array的第二個引數是[非型別模板引數 Nontype Template Parameters](https://github.com/zhangyachen/zhangyachen.github.io/issues/153): ```c++ // template // class array; ``` 假如使用` Stack s;`,那麼編譯器會報錯: ```c++ /Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/array:126:29: note: template parameter has a different kind in template argument template ^ main.cc:22:33: note: previous template template parameter is here template ^ ``` (完) **朋友們可以關注下我的公眾號,獲得最及時的更新:** ![image](https://user-images.githubusercontent.com/14103319/92430320-11583200-f1c7-11ea-940d-1e297d2f39