模板参数自动推导

在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 所带参数的类型,自动推导出了函数模板的参数。

这个解决方案其实并不太理想,这是因为:

  1. 我们需要记住 make_pair, make_tuple 这类用于构造模板类的惯用法。
  2. 有些 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尝鲜:类模板中的模板参数自动推导的更多相关文章

  1. C++17尝鲜

    https://cloud.tencent.com/developer/article/1351910 [译]C++17,optional, any, 和 variant 的更多细节 用户261520 ...

  2. [原创]java WEB学习笔记109:Spring学习---spring对JDBC的支持:使用 JdbcTemplate 查询数据库,简化 JDBC 模板查询,在 JDBC 模板中使用具名参数两种实现

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  3. C++学习35 模板中的函数式参数

    C++对模板类的支持比较灵活,模板类的参数中除了可以有类型参数,还可以有普通参数.例如: template<typename T, int N> class Demo{ }; N 是一个普 ...

  4. C++17尝鲜:变长 using 声明

    using 声明 先来看 using 声明在类中的应用: 代码1 #include <iostream> using namespace std; struct A { void f(in ...

  5. VB类模块中属性的参数——VBA中Range对象的Value属性和Value2属性的一点区别

    在VB中,属性是可以有参数的,而VBA中属性使用参数非常常见.比如最常用的:Worksheet.Range("A1:A10")  VB的语法,使用参数的不一定是方法,也有可能是属性 ...

  6. C++17尝鲜:在 if 和 switch 语句中进行初始化

    初始化语句 在C++17中,类似于 for 语句,在 if 和 switch 语句的判断条件之前也能加上初始化语句,语法形式如下: if (初始化语句; 条件) 语句 else 语句 switch ( ...

  7. C++17尝鲜:variant

    variant variant 是 C++17 所提供的变体类型.variant<X, Y, Z> 是可存放 X, Y, Z 这三种类型数据的变体类型. 与C语言中传统的 union 类型 ...

  8. C++17尝鲜:编译期 if 语句

    Constexpr If(编译期 if 语句) 以 if constexpr 打头的 if 语句被称为 Constexpr If. Constexpr If 是C++17所引入的新的语法特性.它为C+ ...

  9. C++17尝鲜:结构化绑定声明(Structured Binding Declaration)

    结构化绑定声明 结构化绑定声明,是指在一次声明中同时引入多个变量,同时绑定初始化表达式的各个子对象的语法形式. 结构化绑定声明使用auto来声明多个变量,所有变量都必须用中括号括起来. cv-auto ...

随机推荐

  1. JUC集合之 ArrayBlockingQueue

    ArrayBlockingQueue介绍 ArrayBlockingQueue是数组实现的线程安全的有界的阻塞队列. 线程安全是指,ArrayBlockingQueue内部通过"互斥锁&qu ...

  2. js object对象赋值bug和对象复制clone方法

    最近在写程序的时候发现,如果新建一个object对象objb,初始化值为obja,如果改变了objb对象的字段值,那么obja也会随之改变,看来对象赋值传递的是一个引用. 代码重现: <scri ...

  3. golang fmt用法举例

    下标与参数的对应 例子如下: package main import ( "fmt" ) func main() { num := 10 fmt.Printf("num: ...

  4. Openwrt TTL线刷

    1.接通串口,网线: 2.打开串口软件SecureCRT: 3.按复位键,不断地出现信息: 4.2秒内按任意键停下来,出现uboot> 5.输入httpd 6.打开网页,输入ip 7.开始更新, ...

  5. robots写法及相关命令介绍

    当一个搜索蜘蛛访问一个站点时,它会首先检查该站点根目录下是否存在robots.txt,如果存在,搜索机器人就会按照该文件中的内容来确定访问 的范围:如果该文件不存在,所有的搜索蜘蛛将能够访问网站上所有 ...

  6. CentOS Linux解决Device eth0 does not seem to be present 但是没有发现eth1

    http://www.linuxidc.com/Linux/2012-12/76248.htm 此标题已经是有人写过的了.但是为什么拿来重写? 我复制完,没有发现有eth1这个网卡 为什么呢?需要选中 ...

  7. lwip编译选项

    修改默认选项时,不要修改opt.h文件,通过lwipopts.h修改. 和内存管理以及TCP发送性能相关的选项 // 为1时使用系统库malloc/free进行内存管理 #ifndef MEM_LIB ...

  8. bzoj2656 数列

    Description 小白和小蓝在一起上数学课,下课后老师留了一道作业,求下面这个数列的通项公式: A[0]=0 A[1]=1 A[2n]=A[n] A[2n+1]=A[n]+A[n+1] 小白作为 ...

  9. zufeoj Electrification Plan (最小生成树,巧妙设e[i][j]=0)

    Electrification Plan 时间限制: 1 Sec  内存限制: 128 MB提交: 31  解决: 13[提交][状态][讨论版] 题目描述 Some country has n ci ...

  10. html如何设置打印样式?

    转自网络,忘记出处了. html/jsp/网页/打印相关/打印预览/js设置页眉页脚 <html> <head>    <title>打印相关</title& ...