c++11-17 模板核心知識(十二)—— 模板的模板引數 Template Template Parameters
阿新 • • 發佈:2020-12-04
- [概念](#概念)
- [舉例](#舉例)
- [模板的模板引數的引數匹配 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