C++17尝鲜:类模板中的模板参数自动推导
模板参数自动推导
在C++17之前,类模板构造器的模板参数是不能像函数模板的模板参数那样被自动推导的,比如我们无法写
std::pair a{1, "a"s}; // C++17
而只能写
std::pair<int, string> a{1, "a"s}; // C++14
为了弥补这一缺陷,标准库为我们提供了 std::make_pair 函数,通过函数模板的模板参数自动推导的功能,
免去我们在构造 pair 时写模板参数的麻烦。
auto a = std::make_pair(1, "a"s); // C++14
// 相当于
// std::pair<int, string> a = std::make_pair<int, string>(1, string("a"));
// 这里编译器根据 std::make_pair 所带参数的类型,自动推导出了函数模板的参数。
这个解决方案其实并不太理想,这是因为:
- 我们需要记住 make_pair, make_tuple 这类用于构造模板类的惯用法。
- 有些 make_XXX 函数在功能上并不等价于类模板的构造器,比如 make_shared 等等。
在C++17中,这个问题得到了解决,类模板构造器的模板参数同样能够被自动推导
std::pair a{1, "a"s}; // C++17
// 相当于
// std::pair<int, string> a{1, "a"s};
// 和函数模板一样,这里编译器根据 std::pair 构造器所带参数类型,自动推导出了构造器模板的参数。
由此我们不再需要 std::make_pair 之类的辅助函数了。
示例
#include <iostream>
#include <vector>
#include <functional>
#include <string>
#include <map>
#include <algorithm>
using namespace std;
int main()
{
vector a = {1, 2, 3}; // C++17
// vector<int> a = {1, 2, 3}; // C++14
function f = [](int a){return a + 1;}; // C++17
// function<int(int)> f = [](int a){return a + 1;}; // C++14
tuple t{1, 2,5, "a"s}; // C++17
// tuple<int, double, string> t{1, 2,5, "a"s}; // C++14
// auto t = make_tuple(1, 2,5, "a"s); // C++14
sort(a.begin(), a.end(), greater{}); // C++17
// sort(a.begin(), a.end(), greater<>{}); // C++14
// sort(a.begin(), a.end(), greater<int>{}); // C++11
// map m = {{1, "a"s}, {2, "b"s}}; // {1, "a"s} 这种使用大括号的初始化列表没有类型
// 所以编译器无法自动推导 map 类模板的参数类型
map m = {pair{1, "a"s}, {2, "b"s}}; // C++17
// map<int, string> m = {{1, "a"s}, {2, "b"s}}; // C++14
}
以下内容来自视频 Class Template Argument Deduction
自定义类模板中的应用
template<typename T>
struct Container
{
Container(T* ptr) {} // 构造器 1
Container(T& v) {} // 构造器 2
Container(T const& v) {} // 构造器 3
template<typename D>
Container(T* ptr, D& deleter) {} // 构造器 4
};
struct Deleter {};
int main()
{
Container c{(int*)0}; // 调用构造器 1
int x; Container c2{x}; // 调用构造器 2
Container c3{0}; // 调用构造器 3
Deleter d;
Container c4{(int*)0, d}; // 调用构造器 4
// 以上编译器自动推导的结果都是 Container<int>
}
Automatic deduction guides(自动推断向导)
有些情况下,编译器无法对类模板的参数做出自动推导,比如下面这种模板参数类型是个嵌套类型的情况。
此时我们需要添加自动推断向导来帮助编译器来进行自动推导。
自动推断向导形式如下:
类模板名(参数列表) -> 类模板id
template<typename T>
struct Traits { using type = T; };
template<typename T>
struct Container
{
// 参数类型是嵌套类型,无法进行自动推导
Container(typename Traits<T>::type v) {}
};
// 自动推断向导
template<typename T>
Container(T) -> Container<T>;
int main()
{
Container c(0); // 编译器自动推导的结果是 Container<int>
}
C++17尝鲜:类模板中的模板参数自动推导的更多相关文章
- C++17尝鲜
https://cloud.tencent.com/developer/article/1351910 [译]C++17,optional, any, 和 variant 的更多细节 用户261520 ...
- [原创]java WEB学习笔记109:Spring学习---spring对JDBC的支持:使用 JdbcTemplate 查询数据库,简化 JDBC 模板查询,在 JDBC 模板中使用具名参数两种实现
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- C++学习35 模板中的函数式参数
C++对模板类的支持比较灵活,模板类的参数中除了可以有类型参数,还可以有普通参数.例如: template<typename T, int N> class Demo{ }; N 是一个普 ...
- C++17尝鲜:变长 using 声明
using 声明 先来看 using 声明在类中的应用: 代码1 #include <iostream> using namespace std; struct A { void f(in ...
- VB类模块中属性的参数——VBA中Range对象的Value属性和Value2属性的一点区别
在VB中,属性是可以有参数的,而VBA中属性使用参数非常常见.比如最常用的:Worksheet.Range("A1:A10") VB的语法,使用参数的不一定是方法,也有可能是属性 ...
- C++17尝鲜:在 if 和 switch 语句中进行初始化
初始化语句 在C++17中,类似于 for 语句,在 if 和 switch 语句的判断条件之前也能加上初始化语句,语法形式如下: if (初始化语句; 条件) 语句 else 语句 switch ( ...
- C++17尝鲜:variant
variant variant 是 C++17 所提供的变体类型.variant<X, Y, Z> 是可存放 X, Y, Z 这三种类型数据的变体类型. 与C语言中传统的 union 类型 ...
- C++17尝鲜:编译期 if 语句
Constexpr If(编译期 if 语句) 以 if constexpr 打头的 if 语句被称为 Constexpr If. Constexpr If 是C++17所引入的新的语法特性.它为C+ ...
- C++17尝鲜:结构化绑定声明(Structured Binding Declaration)
结构化绑定声明 结构化绑定声明,是指在一次声明中同时引入多个变量,同时绑定初始化表达式的各个子对象的语法形式. 结构化绑定声明使用auto来声明多个变量,所有变量都必须用中括号括起来. cv-auto ...
随机推荐
- JUC集合之 ConcurrentSkipListMap
ConcurrentSkipListMap介绍 ConcurrentSkipListMap是线程安全的有序的哈希表,适用于高并发的场景. ConcurrentSkipListMap和TreeMap,它 ...
- CDN、浏览器缓存
CDN是什么? 谈到CDN的作用,可以用8年买火车票的经历来形象比喻: 8年前,还没有火车票代售点一说,12306.cn更是无从说起.那时候火车票还只能在火车站的售票大厅购买,而我所住的小县城并不通火 ...
- hadoop最新版本介绍之dkhadoop版本选择
Hadoop对于从事互联网工作的朋友来说已经非常熟悉了,相信在我们身边有很多人正在转行从事hadoop开发的工作,理所当然也会有很多hadoop入门新手.Hadoop开发太过底层,技术难度远比我们想象 ...
- ubuntu初次设置root密码
初次安装ubuntu创建的用户不是root用户,但是需要root权限的时候又需要密码,那么如何设置密码呢? 很简单.如下几步操作
- java日期格式转换工具类
原文地址:http://blog.csdn.net/zhiweianran/article/details/7991531 package com.ace.backoffice.utils; impo ...
- 切图js
首先引用一段关于拖动,缩放,剪切的基础代码 /* * 作者:http://cloudgamer.cnblogs.com/ * * 改进与增强 * 作者:http://yoker.sc0826.com/ ...
- flutter初探
这两天看了下flutter,感觉这两年可能会爆发,所以尝试在mac和win10上面跑了下hello world... 移动技术简介 原生开发 跨平台技术简介 H5+原生(Cordova.Ionic.微 ...
- css调用方式的方法
1.内部样式表(位于 <head> 标签内部) <html><style>.box{display:inline}p { color: rgb(255,0,0); ...
- java web程序 上机考试登陆界面设计实现
今天是java web上机.做一个登陆注册的界面.要求:jsp.mysql数据库,js做一个美观的界面.功能.可以添加 更多啊.我做的界面被老师狠狠的扣了分.问题在于.当用户没有输入任何信息(没有输入 ...
- OS信号实现Java异步通知
OS信号实现Java异步通知本文将结合操作系统的信号机制,来尝试实现一个简单的,不依赖功能环境的Java异步通知功能.没有特殊说明,本文所有的示例,都是基于Linux.信号简介信号是在软件层次上对中断 ...