IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++新标准-C++11/14(第一讲:语言部分) -> 正文阅读

[C++知识库]C++新标准-C++11/14(第一讲:语言部分)

1. 可变模板参数

在这里插入图片描述
这在面向对象的课程就讲过了。
值得注意的是,2与3是可以并存的。在VS2019中测试如下:
在这里插入图片描述
可以看到都是调用第一个,说明

template<typename T, typename... Types>
void print(const T& firstArg, const Types&... args)

更加特化,而另一个更泛化,优先调用更特化版本的。
下面两张图为标准库的一些片段,可以看到一些调用流程,学习一下:
在这里插入图片描述
在这里插入图片描述

2. Space in Template Expressions

其实就是支持现在常见的写法了,之前一定要加空格。
在这里插入图片描述

3. nullptr and std::nullptr_t, auto

新增nullptr,见下图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4. Uniform Initialization

一致性初始化:现在新特性下可以统一用 {} 来初始化
在这里插入图片描述
上图有深入的实现的理解。

5. Initializer Lists

如第四点那张图,编译器看到大括号 {t1, t2, …, tn} 就把他们看作一包(initializer_list)
在这里插入图片描述
在这里插入图片描述
上面那样设初值需要initializer_list类来实现,这在标准库的实现里有很大的影响。
在这里插入图片描述
在这里插入图片描述
如上图,P s={77, 5}; 也是调用构造函数。
一包(initializer_list) 可以接受任意个数。
如果没有版本2,那么在P q{77, 5}; 就会调用1,这时候编译器会把参数拆开,一个一个传给构造函数(而在之前则是直接看作一包!)。同样s也可以,但是r就编译不过去(有3个参数,但构造函数只有两个)。
而他的内部是array实现的:
在这里插入图片描述
在这里插入图片描述
回过来看:
在这里插入图片描述
在这里插入图片描述
如上可见其在标准库所占的成分,影响很大。
在这里插入图片描述
并且通过这样的方式,我们可以实现min和max函数一次传一包参数。

6. explicit for ctors taking more than one argument

2.0版本之前:
在这里插入图片描述
explicit主要用在构造函数之前。这在之前的面向对象下有讲过。
2.0之前只有单一实参可以。
2.0之后:
在这里插入图片描述

7. range-based for statement

在这里插入图片描述
编译器解释如下:
在这里插入图片描述
如下图加了explicit就不能这样用(因为赋值时要做转换,但explicit不允许):
在这里插入图片描述

8. =default, =delete

这两个关键词主要用在构造函数、拷贝构造、拷贝赋值等函数上,这些特殊的函数也叫Big-Three,而当2.0之后多了右值引用,也叫Big-Five,如下图:
在这里插入图片描述
在这里插入图片描述
C++2.0之前的复习:
在这里插入图片描述
即空的class编译器会自动声明这些默认版本的函数。且都是inline的。
在这里插入图片描述
只要这个类带有pointer-member,基本就要写Big-Three,而不带则一般不需要写。
比如上图复数类的实现没有指针成员,则没有Big-Three,而string有:
在这里插入图片描述
再往下看:
在这里插入图片描述
=delete告诉编译器不要定义他。
而像NoCopy这样子太绝对了。现实中我们还可以开一个后门,把拷贝构造、拷贝赋值写在private里:
在这里插入图片描述
这样就只有friends和members可以去copy。

9. Alias Template

化名:
在这里插入图片描述
如上图,可以把vector指定自己的分配器,而用别名就避免了每一次使用都要写那么长。
而使用宏则无法达到相同效果。
但是使用化名无法对化名做特化。(化名无法代表本尊)
在这里插入图片描述
本意想写个函数测试容器可搬不可搬(move),来测试他们的时间(这里没写出来),但是放进来的参数一定是object,怎么能拿他的type去做文章呢?简直是天方夜谭。
后来改动如上图右边,一个typename后面加()表示临时的变量,想拿这样的对象拿来用,但是Container怎么确定是一个模板呢,仍然是天方夜谭。
再次改动仍然不认识:
在这里插入图片描述
最后改动:
在这里插入图片描述
想要得到容器内部的类型需要萃取机traits。可以办到,但还是难以实现原本的接口。
但要是还是不死心要像之前一样弄出接口如(list, MyString)呢?下面引出模板模板参数以及化名的用法:

10. Template template parameter

在这里插入图片描述
上图事实上有点不好理解(class那里省略了T),可以看一下之前面向对象下的课件:
在这里插入图片描述
然而这样使用仍然会报错。
观察标准库源码,知道vector模板第二个参数有默认值,而在模板模板参数无法推出来。
解决方法:
在这里插入图片描述

11. Type Alias, noexcept, override, final

其实Type Alias类型别名就类似typedef:
在这里插入图片描述
using的用法:
在这里插入图片描述
在某一些class里头写如using _Base::_M_allocate;那么之后就可以只写_M_allocate而不用加原来的类::

在某条件下一定不会发出异常:
在这里插入图片描述
这里void foo () noexcept; 的后面的条件默认为true,即一定不会发出异常。
异常如果抛出没有被处理,就会一直往源头去抛,比如A调用B,B抛出异常,但A没处理,就会继续往调用A的地方去传递。要是一直没有处理异常程序就会崩溃。
在这里插入图片描述
如上,通过通知C++noexcept告诉上层vector可以用搬移的函数。(只有vector会成长grows)避免copy,效率提升。
在这里插入图片描述
override需要函数签名完全相同。这个关键字帮助编译器检查。(把要重载的心意告诉编译器)
在这里插入图片描述
final:第一种用法:
修饰class,告诉别人不能被继承
修饰函数function,告诉别人(比如继承过来)不能复写

12. decltype

得到对象的type:
在这里插入图片描述
可以把这个关键字想象成typeof:
在这里插入图片描述
有三种用法,我们分别来看一下:

  1. 让编译器通过。
    在模板中不知道真正的x + y是什么类型,比如苹果类 + 梨子类,可能得到的是水果类(向上转型了),但是我们不知道究竟是什么。
    但是简单的像上面这样写是通不过的,我们要使用auto关键字,结合decltype指定方式。有点点像lambda表达式。
    在这里插入图片描述
  2. 适用于元编程(metaprogramming,不要想的太严肃了,先想成就是在函数模板里用)
    在这里插入图片描述
    只要用到了T::如上图的 T::iterator,就要加typename,以显示地告诉编译器T::iterator是一个类型名。
    而由于模板只是一个半成品,用的时候如图传入一个复数的临时对象,但是复数类不是容器没有iterator,就会报错。
  3. lambda
    在这里插入图片描述
    lambda的type是很难写出来的,一般都是直接auto,decltype传入容器当作typeof。

13. lambdas

下图中间的那一段的小括号就不是产生临时对象了,而是执行,但是一般我们会按下面那一段去做:
在这里插入图片描述
mutable(中括号捕获的值可否改变), throwSpec(一个函数可不可以抛出异常), retType(返回类型) 三者有一个就要写():
在这里插入图片描述
注意看下图左侧的结果,传入的id不是按引用传递,所以不会影响外头的id:
在这里插入图片描述
在上图中,如果没有写mutable,就不能在里头id++。

再来看下图,传引用就会改变外部的id,而传值又不为mutable就会报错:
在这里插入图片描述

在这里插入图片描述
又回到了decltype的用法,用来传递lambda的type:
在这里插入图片描述
由于lambda的语法,如法给他构造函数或是赋值操作。所以必须要把lambda传给构造函数(如上的cmp传递给coll容器),否则就会调用默认构造函数,然后就会报错。
所以得如上这样写出:

std::set<Person, decltype(cmp)> coll(cmp);

在这里插入图片描述

14. Variadic Templates 1

重新回到开头:
在这里插入图片描述
七个大例子:
在这里插入图片描述

15. Variadic Templates 2

用Variadic Templates重写printf(),很简单就实现了出来:
在这里插入图片描述

16. Variadic Templates 3

参数type相同的话用initializer_list就可以了:
在这里插入图片描述
但是这样写max的参数必须要用{}来产生临时对象,变成initializer_list。

我的补充

这里我查看cplusplus网站:
https://www.cplusplus.com/reference/algorithm/max/?kw=max
在这里插入图片描述
可见max有三种(这里我们以C++11的标准来看,14和11差不多),默认为两个参数,即我们平常使用的

std::cout << std::max(1, 4) << std::endl;

第一种其实不用包含头文件algorithm也能用。
而第二种和第三种则必须要包含头文件algorithm。
而第二种则是可以给一个比较方法。我们先来读读标准库源码(测试环境VS2019):
在这里插入图片描述
可以看到,标准库首先用了noexcept关键字(这在前面说过,如果为true则代表一定不会抛出异常)来让程序更健壮(后面注释也说了strengthened)。
然后可以看到模板参数的_Pred其实就是一个仿函数,如果为真则这个max结果返回_Right,为假则返回_Left,我写的测试程序如下:

#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
	pair<int, int> FirstArg = { 1, 10 };
	pair<int, int> SecondArg = { 100, 2 };
	pair<int, int> DefaultResult = max(FirstArg, SecondArg);
	pair<int, int> CompResult = max(FirstArg, SecondArg, [](pair<int, int>a, pair<int, int>b) {return a.second < b.second; });
	cout << "DefaultResult: " << DefaultResult.first << " " << DefaultResult.second << endl;
	cout << "CompResult: " << CompResult.first << " " << CompResult.second << endl;
	return 0;
}

程序运行结果:
在这里插入图片描述
可以看到,默认的是比较pair的第一个数的大小,如果第一个数相等则再比较第二个数。所以返回的是SecondArg.
而使用max的第二种方法,我们给了一个lambda表达式,用来比较两个pair的second,如果第一个的second比第二个的大就返回false,false则对应返回_Left,即这里返回的是FirstArg.达到了比较pair第二个参数的目的。
第三种方法即传入多个参数,必须要用{}包起来,测试程序如下:

#include <iostream>
#include <algorithm>
using namespace std;

int main()
{
	cout << max({ 1, 2, 3, 4, 5 }) << endl;
	return 0;
}

多个参数的时候必须要用{}包起来,实际上在这里编译器会将其推导为initializer_list类型,产生一个initializer_list的临时对象,然后会调用标准库中的(algorithm第9545行):
在这里插入图片描述
这里的_STD实际上就是::std::,接着则会调用:
在这里插入图片描述
可以看到,之后就是简单地在initializer_list中找到最大值就可以了。简单提一句,initializer_list的底层就是array去实现的。

17. Variadic Templates 4

在这里插入图片描述

18. Variadic Templates 5

在这里插入图片描述

19. Variadic Templates 6

前面的例子都是通过分解Args去递归调用函数。
这里用类模板来用于递归继承:
在这里插入图片描述
这里使用private继承,非常好:
在这里插入图片描述
这里正规来讲只要在这里写了::(Head::type)就要在前面写上typename,不过有的编译器不写也能过。
而这里的tuple的构造函数,除了设定m_head,还调用了父类的构造函数:inherited(vtail…)
虽然看起来逻辑很正确,却在Head::type报了错:
在这里插入图片描述
因为这里的Head是int、float、string,怎么能回答type呢?
所以改为:
在这里插入图片描述
不过其实直接拿Head来用就行了…:
在这里插入图片描述

20. Variadic Templates 7

之前讲Variadic Templates用于递归继承,这里讲Variadic Templates用于递归复合:
在这里插入图片描述
这里Variadic Templates所有的例子都是递归:递归调用、递归创建、递归继承、递归复合

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-01 14:19:22  更:2021-08-01 14:20:58 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/1 9:42:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码