概念

一个模板的参数是模板类型。

举例

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::dequeCont不匹配。标准库的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的更多相关文章

  1. c++11-17 模板核心知识(二)—— 类模板

    类模板声明.实现与使用 Class Instantiation 使用类模板的部分成员函数 Concept 友元 方式一 方式二 类模板的全特化 类模板的偏特化 多模板参数的偏特化 默认模板参数 Typ ...

  2. c++11-17 模板核心知识(一)—— 函数模板

    1.1 定义函数模板 1.2 使用函数模板 1.3 两阶段翻译 Two-Phase Translation 1.3.1 模板的编译和链接问题 1.4 多模板参数 1.4.1 引入额外模板参数作为返回值 ...

  3. c++11-17 模板核心知识(五)—— 理解模板参数推导规则

    Case 1 : ParamType是一个指针或者引用,但不是universal reference T& const T& T* Case 2 : ParamType是Univers ...

  4. c++11-17 模板核心知识(十五)—— 解析模板之依赖型类型名称与typename Dependent Names of Types

    模板名称的问题及解决 typename规则 C++20 typename 上篇文章c++11-17 模板核心知识(十四)-- 解析模板之依赖型模板名称 Dependent Names of Templ ...

  5. c++11-17 模板核心知识(十一)—— 编写泛型库需要的基本技术

    Callables 函数对象 Function Objects 处理成员函数及额外的参数 std::invoke<>() 统一包装 泛型库的其他基本技术 Type Traits std:: ...

  6. c++11-17 模板核心知识(十四)—— 解析模板之依赖型模板名称(.template/->template/::template)

    tokenization与parsing 解析模板之类型的依赖名称 Dependent Names of Templates Example One Example Two Example Three ...

  7. 第二十二章 跳出循环-shift参数左移-函数的使用 随堂笔记

    第二十二章 跳出循环-shift参数左移-函数的使用 本节所讲内容: 22.1 跳出循环 22.2 Shift参数左移指令 22.3 函数的使用 22.4 实战-自动备份mysql数据库和nginx服 ...

  8. c++11-17 模板核心知识(八)—— enable_if<>与SFINAE

    引子 使用enable_if<>禁用模板 enable_if<>实例 使用Concepts简化enable_if<> SFINAE (Substitution Fa ...

  9. Testlink1.9.17使用方法(第十二章 总结)

    第十二章 总结 QQ交流群:585499566 TestLink用于进行测试过程中的管理,通过使用TestLink提供的功能,我们可以将测试过程从:测试需求.测试设计.到测试执行.完整的管理起来,同时 ...

随机推荐

  1. yython爬虫基础知识入门

    Python爬虫 关注公众号"轻松学编程"了解更多. 大纲: 1.获取响应 urllib(python3)/urllib2-urllib(python2) requests(url ...

  2. Json Master masters JSON!

    对于一个软件开发人员, JSON 是最熟悉的东西之一了, 每一个开发人员基本上每一天都会跟 JSON 打交道. 作为一个大前端开发人员, 当看到从服务器返回的 JSON 数据时, 尤其是大数据量或者复 ...

  3. 阿里巴巴开发手册强制使用SLF4J作为门面担当的秘密,我搞清楚了

    之前已经详细.全面地介绍了 Log4j,相信小伙伴们已经完全掌握了.那我在读嵩山版的阿里巴巴开发手册(没有的小伙伴,记着找我要)的时候,就发现了一条「强制」性质的日志规约: 应用中不可以直接使用日志系 ...

  4. Spark编程练习题

    import org.apache.spark.sql.SparkSessionval spark = SparkSession.builder().appName("Spark SQL b ...

  5. ubuntu18.04下stlink的一种安装方法

    安装前准备: 从软件包存储库中安装以下软件包: git gcc或clang或mingw32-gcc或mingw64-gcc(C编译器:很可能已经存在gcc) build-essential (在基于D ...

  6. 13flask密码加密

    一,了解密码加密方式 密码具有私有性较强的特性,预测密码加密对个人隐私的保护有这非常大的作用.在用flask搭建网站时候若服务器有被攻破的风险,要是用户表中密码字段也被拿走,后果将不堪设想. 在密码保 ...

  7. 浮动布局问题多,还是用inline-block吧

    说说知识陈旧的问题. 目前我的前端开发知识积累最大的问题就是版本问题,也许我已经经历了很多,尝试了很多, 但是有些知识的版本已经过时了,而我还没有来得及更新它们.更悲剧的可能是有些部分我还没有意识到. ...

  8. 一看就懂的MySQL的FreeList机制

    Hi,大家好!我是白日梦! 今天我要跟你分享的MySQL话题是:"了解InnoDB的FreeList吗?谈谈看!" 本文是MySQL专题的第 7 篇,共110篇. 一.回顾 前面几 ...

  9. 链路层输出 -qdisc

    二层发送中,实现qdisc的主要函数是__dev_xmit_skb和net_tx_action,本篇将分析qdisc实现的原理,仅对框架进行分析. 其框架如下图所示 qdisc初始化 pktsched ...

  10. MVCC(转)

    什么是 MVCC MVCC (Multiversion Concurrency Control) 中文全程叫多版本并发控制,是现代数据库(包括 MySQL.Oracle.PostgreSQL 等)引擎 ...