c++11-17 模板核心知识(十二)—— 模板的模板参数 Template Template Parameters
概念
一个模板的参数是模板类型。
举例
在c++11-17 模板核心知识(二)—— 类模板 中,如果我们想要允许指定存储Stack元素的容器,是这么做的:
template <typename T, typename Cont = std::vector<T>>
class Stack {
private:
Cont elems; // elements
......
};
使用:
Stack<double,std::deque<double>> dblStack;
但是这样的缺点是需要指定元素类型两次,然而这两个类型是一样的。
使用模板的模板参数(Template Template Parameters),允许我们在声明Stack类模板的时候只指定容器的类型而不去指定容器中
元素的类型。例如:
template <typename T, template <typename Elem> class Cont = std::deque>
class Stack {
private:
Cont<T> 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();
}
...
};
使用:
Stack<int, std::vector> vStack; // integer stack that uses a vector
与第一种方式的区别是:第二个模板参数是一个类模板:
template<typename Elem> class Cont
默认值从std::deque<T>改为了std::deque.
在C++17之后,模板的模板参数中的class也可以使用typename,但是不可以使用struct和union:
template <typename T,
template <typename Elem> typename Cont = std::deque>
class Stack { // ERROR before C++17
...
};
......
template<template<typename X> class C> // OK
void f(C<int>* p);
template<template<typename X> struct C> // ERROR: struct not valid here
void f(C<int>* p);
template<template<typename X> union C> // ERROR: union not valid here
void f(C<int>* p);
当然,由于模板的模板参数中的Elem没有用到,可以省略:
template <typename T, template <typename> class Cont = std::deque>
class Stack {
...
};
另外注意一点,模板的模板参数中的模板参数,只能和模板的模板参数配合用。有点饶,举个例子:
template<template<typename T, T*> class Buf> // OK
class Lexer {
static T* storage; // ERROR: a template template parameter cannot be used here
...
};
模板的模板参数的参数匹配 Template Template Argument Matching
大家可以尝试自己编译一下上面的代码,可能会出现下列问题:
error: template template argument has different template parameters than its corresponding template template parameter
template <typename T, template <typename Elem> 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 <class _Tp, class _Allocator /*= allocator<_Tp>*/>
意思是std::deque和Cont不匹配。标准库的std::deque有两个参数,还有一个默认参数Allocator :
template <class _Tp, class _Allocator = allocator<_Tp> > class _LIBCPP_TEMPLATE_VIS deque;
解决办法一
将Cont和std::deque的参数匹配即可:
template <typename T,
template <typename Elem, typename Alloc = std::allocator<Elem>>
class Cont = std::deque>
class Stack {
......
};
这里的Alloc没有用到,同样可以省略。
成员函数定义举例:
template<typename T, template<typename,typename> class Cont>
void Stack<T,Cont>::push (T const& elem) {
elems.push_back(elem); // append copy of passed elem
}
解决办法二
利用c++11-17 模板核心知识(四)—— 可变参数模板 Variadic Template
template <typename T,
template <typename......>
class Cont = std::deque>
class Stack {
......
};
但是,这点对于std::array无效,因为std::array的第二个参数是非类型模板参数 Nontype Template Parameters:
// template<typename T, size_t N>
// class array;
假如使用 Stack<int,std::array> s;,那么编译器会报错:
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/array:126:29: note: template parameter has a different kind in template argument
template <class _Tp, size_t _Size>
^
main.cc:22:33: note: previous template template parameter is here
template <typename... Elem>
^
(完)
朋友们可以关注下我的公众号,获得最及时的更新:

c++11-17 模板核心知识(十二)—— 模板的模板参数 Template Template Parameters的更多相关文章
- c++11-17 模板核心知识(二)—— 类模板
类模板声明.实现与使用 Class Instantiation 使用类模板的部分成员函数 Concept 友元 方式一 方式二 类模板的全特化 类模板的偏特化 多模板参数的偏特化 默认模板参数 Typ ...
- c++11-17 模板核心知识(一)—— 函数模板
1.1 定义函数模板 1.2 使用函数模板 1.3 两阶段翻译 Two-Phase Translation 1.3.1 模板的编译和链接问题 1.4 多模板参数 1.4.1 引入额外模板参数作为返回值 ...
- c++11-17 模板核心知识(五)—— 理解模板参数推导规则
Case 1 : ParamType是一个指针或者引用,但不是universal reference T& const T& T* Case 2 : ParamType是Univers ...
- c++11-17 模板核心知识(十五)—— 解析模板之依赖型类型名称与typename Dependent Names of Types
模板名称的问题及解决 typename规则 C++20 typename 上篇文章c++11-17 模板核心知识(十四)-- 解析模板之依赖型模板名称 Dependent Names of Templ ...
- c++11-17 模板核心知识(十一)—— 编写泛型库需要的基本技术
Callables 函数对象 Function Objects 处理成员函数及额外的参数 std::invoke<>() 统一包装 泛型库的其他基本技术 Type Traits std:: ...
- c++11-17 模板核心知识(十四)—— 解析模板之依赖型模板名称(.template/->template/::template)
tokenization与parsing 解析模板之类型的依赖名称 Dependent Names of Templates Example One Example Two Example Three ...
- 第二十二章 跳出循环-shift参数左移-函数的使用 随堂笔记
第二十二章 跳出循环-shift参数左移-函数的使用 本节所讲内容: 22.1 跳出循环 22.2 Shift参数左移指令 22.3 函数的使用 22.4 实战-自动备份mysql数据库和nginx服 ...
- c++11-17 模板核心知识(八)—— enable_if<>与SFINAE
引子 使用enable_if<>禁用模板 enable_if<>实例 使用Concepts简化enable_if<> SFINAE (Substitution Fa ...
- Testlink1.9.17使用方法(第十二章 总结)
第十二章 总结 QQ交流群:585499566 TestLink用于进行测试过程中的管理,通过使用TestLink提供的功能,我们可以将测试过程从:测试需求.测试设计.到测试执行.完整的管理起来,同时 ...
随机推荐
- Appium常用操作之「微信滑屏、触屏操作」
坚持原创输出,点击蓝字关注我吧 作者:清菡 博客:oschina.云+社区.知乎等各大平台都有. 目录 一.滑屏操作 1.访问之后,马上就滑屏可以吗? 2.连续实现 2 次滑屏 3.代码 二.模拟触屏 ...
- P5691 [NOI2001]方程的解数
题意描述 方程的解数 求方程 \(\sum_{i=1}^{n}k_ix_i^{p_i}=0(x_i\in [1,m])\) 的解的个数. 算法分析 远古 NOI 的题目就是水 类似于这道题. 做过这道 ...
- CF1413C Perform Easily 题解
毒瘤C题,考场卡我1个小时 首先,这道题难点在哪里?它的最大值与最小值都是浮动的. 怎么办?把最小/最大值固定! 以把最小值固定为例,我们枚举每个音符,并枚举它使用哪条琴弦,将它此时的位置强制其作为最 ...
- Java_包装类
包装类 在实际应用中, 经常需要把基本数据类型转化为对象以便操作. 因此, Java在设计类时, 为每个基本数据类型设计了一个对应的类进行包装, 这样八个和基本数据类型对应的类统称为包装类(Wrapp ...
- SAP S/4HANA 2020安装实录
欢迎关注微信公众号:sap_gui (ERP咨询顾问之家) 今天开始试着安装SAP S/4HANA 2020版本,也是目前SAP ERP最高的版本,总安装文件大小大概50GB,数据库版本必须是HANA ...
- canvas基础[一]探究出初中数学知识
何时用SVG何时用canvas SVG 矢量图,视觉清晰,文件小 <svg viewBox="0 0 100 100"> <circle cx="50& ...
- 剑指Offer-Python(21-25)
21.栈的压入和弹出序列 新建一个栈,将数组A压入栈中,当栈顶元素等于数组B时,就将其出栈,当循环结束时,判断栈是否为空,若为空则返回true. class Solution: def IsPopOr ...
- RPA小结
1--怎么理解RPA? 1)RPA就是机器人流程自动化,根据业务的固定规则,自动完成一些任务(如数据抓取,信息录入,数据处理,自动化运维等),替代人类的重复劳动, 但RPA的发展已经不仅仅满足于此,正 ...
- Jenkins - 部署在Tomcat容器里的Jenkins,提示“反向代理设置有误”
提示"反向代理设置有误"的背景 将jenkins.war放在tomcat容器中运行 访问Jenkins-系统管理,会提示"反向代理设置有误" 如何解决 在tom ...
- 简单STL
string: string s="5418340"; sort(s.begin(),s.end()); cout<<s; /**begin是头迭代器,end是尾迭代器 ...