C++标准11-14

C++标准11-14

2. Variadic Templates

(1)可以用于递归调用函数

对于Variadic Templates来说,要定义好边界的情况

在这里插入图片描述

​ 当args只有一个参数了的时候,第一个参数进去作为firstArg,后面一包的参数为空了,因此会print()一个不带参数的情况,所以我们为了处理边界,要定义一个没有参数的(1)版本的print()。

​ …是pack:模板参数包、函数参数类型包、函数参数包

(2)和(3)是可以并存的吗?

在这里插入图片描述

优先调用更加符合的特化

hash_val有三种版本:整个一包的、第一个参数是size_t的,(它们里面又分两版本、后面还有一个一包参数的)

第一次调用只有(1)符合,所以进入(1),之后固定了第一个参数为seed,加一包,因为现在来说,(2)是特化,相较(1)泛化来说更加吻合,所以调用(2)

(2)递归继承

在这里插入图片描述

继承了tuple<Tail…>并且把第一个参数定义为m_head;

并且把 tuple<Tail…> typedef 为了 inherited;

注意在构造函数的初始化列表当中,初始化vtail时,仍然是调用的base ctor

调用tail时,是把它转为了父类的引用的形式,再去调head,得到父类的那个值

3~4 nullptr、auto

auto只有在这个类名很长或者很复杂的时候使用

Uniform Initialization

在变量的后面直接放大括号,放初始值做初始化

在这里插入图片描述

在初始化vector的时候,编译器看到里面是int,所以在initializer_list的T设为int。

它的内部有一个array<T, n> n是刚刚的个数,编译器也能知道,比如这里有7个。调用时,它变成一包,然后一个一个地进行赋值初始化。

如果函数调用的参数就是initializer_list ,有一个版本就是接收它,那就是整个过去

如果它没有接受 initializer_list 的函数,编译器就会一个一个地拆解并且进行初始化

大括号里是形成一包,有的构造函数就是接收这种包,一包传给了一包

complex构造函数,没有一个是接受一包这种东西的,它只接受一个一个。编译器会把一包分成两个,然后一个一个赋值

5. Initializer list

在这里插入图片描述

想用{5.3} 直接赋值给 int x,是不可以的。会报出ERROR/Warning

用{} 默认赋值是 0 或者 nullptr

在这里插入图片描述

初始化的时候,如果用{}默认是调用一包的那个函数。如果没有那个函数,就拆开用(1)函数

P s={77,5}; 也是调用构造函数

initializer_list背后是一个array

在这里插入图片描述

array就是换一种形式来表达数组,这样就可以用其他算法来处理了。因为算法认的是迭代器。

在这里插入图片描述

除了作用在构造函数中,initializer_list还能作用在=、insert、assign当中

在forwaid_list.h、stl_map.h、stl_algo.h等等中都有initializer_list的版本

在这里插入图片描述

所以在max、min函数里也可以使用

7. Explicit for ctors taking more than one argument

在这里插入图片描述

左边是调用了隐式构造函数

如果右边的话,就没有办法隐式调用

隐式转换

左边的构造函数是non-explicit one argument ctors,只有这种的,才能调用隐式转换

在这里插入图片描述

8. range-based for statement

在这里插入图片描述

一个一个地拿出来遍历,注意拿出来的时候是要assign到左边的变量里面,如果是assign给引用,首先赋值会变的很快(如果你是16个字节,100万个,这样搬动的速率一定是低于4个字节,100万个),其次会直接改变元素内容。

什么容器不能用迭代器直接改变元素内容?

关联式容器都不可以:set、map、mutiset、multimap、unordered_set、unordered_map

在这里插入图片描述

begin()、end()是全局函数

对于容器,也可以用auto来直接的调用遍历,它内部是相当于用了右边的形式

在这里插入图片描述

注意:for-loop的时候,如果类型不一样,就要做转换。但是如果转换的源头是禁止的,那就会报错

9.=default , =delete

如果你自行定义了一个ctor,那么编译器就不会再给你一个default ctor

强制加上=default,就可以重新获得并使用default ctor

加上 =delete,就是代表不要了

在这里插入图片描述

下面两个分别是copy assignment 和 move assignment

在这里插入图片描述

ctor可以有很多,copy ctor 只能有1个。同样地,那个delete也是错的,因为已经写了怎么又delete

copy assignment 一样的,只能有一个

一般的函数没有default

delete可以用于任何函数身上

=0只能用于纯虚函数

对于空的类来说:

在这里插入图片描述

什么类需要有Big-Three?

只要它带有pointer member 几乎可以判定它需要有Big-Three

三法则(英语:rule of three,the Law of The Big Three,The Big Three;三法则,三大定律)在 C++ 程序设计里,它是一个以设计的基本原则而制定的定律,三法则的要求在于,假如类有明显地定义下列其中一个成员函数,那么程序员必须连其他二个成员函数也一同编写至类内,亦即下列三个成员函数缺一不可。

析构函数(Destructor)
复制构造函数(copy constructor)
复制赋值运算符(copy assignment operator)

对于字符串来说,就需要写,而且要写Big-Five

析构函数

拷贝构造函数

移动构造函数

拷贝赋值函数

移动赋值操作

在这里插入图片描述

上面是NoCopy,把所有Copy相关的函数都禁止掉了。

下面是NoDtor, 把拷贝函数禁止掉了

最后面是PrivateCopy,把拷贝构造。是可以由它的友元调用

在这里插入图片描述

进行继承的话,也继承了这样的特性。是可以被自己的家族成员和自己的朋友拷贝。

10. Alias Template

在这里插入图片描述

原来vector的默认分配器是allocator,现在这样写,就可以把分配器固定成MyAlloc

下面是使用模版函数,并且在函数中得到容器的类型

在这里插入图片描述

传给函数的,一定是一个对象。对于左边的这部分,传list, MyString, 显然是不行的

右边改动,选择传递一个对象进去list()(当然这里少了尖尖)、MyString()。但是这样也不对。编译器报错说Container不是一个template

(因为并没有结合起来得知这个容器里的类型,所以把他们两个结合一下!)

在这里插入图片描述

后面把它转为这样:

template + iterator + traits

容器拿到迭代器,迭代器通过traits得到value_type -> Valtype

在这里插入图片描述

那如果通过iterator和traits也无法得出呢?

template template prameter!!

11. Template template prameter

以模版模版参数传入进去的时候,容器类的第一个参数是有的(看右上角),但是容器的第二个参数是没有办法推导出来的,特别是,这第二个参数值还是以第一个参数为参数,所以它推不出来。

在这里插入图片描述

解决办法:传Alias Template,它的第二参数是以第一参数为参数,所以这个绿色的东西只需要接收一个参数就可以了!

在这里插入图片描述

12. Type Alias

using

func 定义为一种函数指针

函数的名称就是地址,那这样直接赋值就是函数指针

using 可以代替typedef

在这里插入图片描述

之前的一些using的使用方法:

在这里插入图片描述

noexcept

在这里插入图片描述

在小括号情况下,这个函数是不会丢出异常的

爆出异常,一直没有人处理,往上一直走传递,如果没人处理就调用std::terminate(), 它里面有std::abort()

在这里插入图片描述

通知C++ move ctor 和 move assigenment 要声明noexcept 尤其是vector

vector 在 grow 的时候, 搬到两倍大的地方

有move版本的,它调用的是move搬动,写了noexcepter vector 才会敢放心地去调用这个函数

链表是没有成长的

deque是一段一段的,你放数据也是两端,中间不会大幅度搬动

红黑树(是树,是节点,也不会大动的)、散列表(篮子下是链表,也不会大动)

override

所谓override,函数的签名是要完全一样的,就算是变量类型不一样,写错了。也是不一样的,他会认为你是新函数,而不是重载,因此他不会报错。但是如果你标明了override,他会给你提示。

在这里插入图片描述

final

(1)写了final 修饰class,就不可以再继承了

(2)如果是针对虚函数写了final,就不可以被override了

在这里插入图片描述

13. decltype

关键字

在这里插入图片描述

已经存在的typeof 是定义不完整的

所以c++11提出了decltype:通过对象取出type

它的应用分成三种:

(1) 用来宣告和声明一个return types

​ 把+add 设计为一个模版函数

​ 设计的时候完全不知道T1和T2是什么,说不定他们可以相加,说不定他们完全不能相加

decltype是找出一个表达式的类型(它先执行x+y,让编译器给推一下它是返回什么类型)

在这里插入图片描述

上面那样写是不对的,因为还不知道x,y是什么的,所以要按下面的写法。

先写成auto,最后指明是decltype(x+y)

这种指定方式(auto 、->)和lambda很像

(2)适用于元编程

函数模版,接受一个type P,下面通过obj得到这个对象的迭代器的类型

代替了使用 typedef typename T::iterator iType;

(注意有的对象没有迭代器,编译会不通过。模版只是半成品)

在这里插入图片描述

只要加上::,前面就要加上typename,帮助编译器确定这整个确实是一个typename,否则编译器会犹豫

(3)used to pass the type of lambda

用[]去表示lambda, 当我们需要这个函数的类型的时候

decltype(cmp)

在这里插入图片描述

14. Lambdas

lambda 定义一个inline的函数,并且可以用作为一个参数或者局部对象

lambda 改变了c++标准库的用法。

比如原来在调用排序算法的时候要放进去仿函数说明比较规则,现在放lambda就可以了

在这里插入图片描述

上面的没有意义,因为它作为临时的,也没有被调用。

中间加()的方式就是直接调用函数了。但是这和直接写里面那几行代码也没什么区别

下面的方式是好的,赋值给一个auto l,最后再用l来调用

在这里插入图片描述

mutable 可变的

没有返回类型,可以用->表示。

当三个optional参数有任何一个的时候,小括号就必须有。其他情况下需要有接收参数的时候才需要小括号

[…]里面放的是取用外部的变量,是传值??还是传引用

()里面放的是待新接收的参数

lambda是等同于匿名的函数对象

在这里插入图片描述

左边等同于右边

注意最后的调用结果。编译器在编译lamda的时候它是会认为id是0的,它不会再管你后面对id重新修改的值。

并且后面再次调用的时候,它用的已经是自己的id,在自己原来的基础上加。并且不会影响外部的id

如果不写mutable id是不能++的

在这里插入图片描述

如果传的是& 引用,会收到外界的影响。

可以不加mutable,注意它和外界此时就是同步了的。它还调用了参数。所以参数其实里面从7变成了9

最后右边的定义。函数是只能读不能写。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7evouVuA-1664890735918)(C:\Users\DELL\AppData\Roaming\Typora\typora-user-images\image-20221004105019386.png)]
代替写成下面仿函数这样。

我们直接用lambda 来代替

在这里插入图片描述

在构造set的时候,传入比较函数的返回值类型。并且后面调用构造函数的时候,是调用那种带Compare的构造函数。可以用decltype 拿到 。

如果没有写出传的对象(cmp)的话,那么它就会默认调用它set类默认的Compare函数 less 函数

由于lambda奇特的语法,他并没有默认构造函数和赋值操作

如果!!!这样写

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

你把lambda放进来了,但是没有放后面参数进来,他就会调用set() 函数,后面紧接着会调用lamda的默认构造函数。但是lambda没有。

在这里插入图片描述

用lambda代替仿函数,仿函数太powerful了(在例子比较简洁的情况下)

lambda 是inline function 右边那样写不是inline

15-21. Variadic Templates

例1

在这里插入图片描述

(1)和 (3) 可以并存,(1)比较特化,(3)是永远不会调用起来的

例2

借用Variadic Templates 写 printf

在这里插入图片描述

根据后面的参数进行分割

分割之后用cout<< 进行丢

例3

设计一个函数__max_element,检测一堆数据里面最大的那个

这里是在说。如果要比较:参数个数不限的,类型都一样的,就用一个initializer_list就可以了

在这里插入图片描述

max(initializer_list里包含了initializer_list参数),他里面调用了max_element函数,把array的头尾指针传入了迭代器中。

__max_element里还调用了怎么样比大小的仿函数(函数对象)

例4

maximum

利用分解的形式把一包的成员和max函数结合起来

第一次调用,一和后面那一包还没法比,它是整个调用完然后返回去的

在这里插入图片描述

例5

类模版

以异于一般的方式处理first元素和last元素

使用sizeof…()获得元素个数

在这里插入图片描述

首先定义tuple,并且定义cout的操作符重载

第一个参数是ostream& os 操作符

第二个参数是那个tuple

下面调用了PRINT_TUPLE类,它的print里有递归地创建新的对象,并且给IDX+1,创建完对象后马上调用print。调用上面/下面的模版函数,下面的是边界。借由这种方式知道现在在处理第几个参数,我就知道我是不是在处理最初的/最后的元素

MAX在整个运作过程是不会变的

这里取出tuple参数是使用了get(t) -> tuple专用函数,然后打印,并且下一个输出什么?看它是不是最后一个!

注意最后一次创建对象 struct PRINT_TUPLE<MAX, MAX, Args…>时,它的print函数就定义为空了

例6

make_tuple 是一种方便的创建tuple的函数

也可以tuple<x, x, x, x> (x,x,x,x) 这样来创建

用于递归继承

在这里插入图片描述

1+一堆n,首先把第一个拿来声明变量,剩下的n拿来做继承

对于例子来说,

首先声明了41 然后把剩下两个拿来做继承

注意继承关系,子类对象内存里有父类的part在里面,它的父类的地址是要在它上面的

首先他们之间用private继承,因为他们之间并不是is a 的关系,只是为了要拿到内存的这一继承体系

把尾部的那一个包定义为inherited

tail() 是把自己转为 inherited类型

注意初始化列表中 inherited是调用父类的构造函数

但是在编译时是会出错的

Head::type int 、float、 string是没有type的

在这里插入图片描述

这样也可以,Head本身就是一个类型

在这里插入图片描述

私有继承:使用私有继承,基类的公有成员和保护成员都将成为派生类的私有成员,只可以在派生类的成员函数中使用

例7. 用于递归组合

可不可以内含,递归地组合?

typedef 了 tup<Tail…> 为 composited

把这个类定义为了tup

注意这里tail的返回一定要是composited& ,你拿到的仅仅是copy版本,如果后面要改值的话是改不到的

上面也要定义好空的tup<>{}

递归创建、递归继承、递归组合
在这里插入图片描述

template<> class tup<> {}; 这是模版特化。指定类型为空

23. Rvalue references

解决非必要的拷贝,可以去偷右边的内容。steal

在这里插入图片描述

临时对象也是右值

为什么对于string 右值还可以赋值?

complex 类也是如此,可以赋值

最常见的右值:临时对象

在这里插入图片描述

函数返回的东西是右边值,想要取它的地址,是会报错的

在这里插入图片描述

传进来的是右值引用(临时对象)的话,就会调用(2)

要偷的人是MyString,也就是这里的Vtype,偷的时候只是把那一块内存的地址变了过来

右值临时对象根本不会再用,就可以用move ctor

作为右值的这里的Vtype(buf),它是被偷了的,后面它就不能再用了

在这里插入图片描述

注意vector是一直这样往末尾插,如果要从前面插,他要往后推,那么就也要意味着做很多次不必要的构造和析构

左值怎么去move(steal)?

通过std::move(xxx) -> 就可以偷了

24. Perfect Forwarding

在这里插入图片描述

到了G4.9,有两个版本的insert。

一个是by reference的,一个是右值引用的

在这里插入图片描述

move 不仅要写 ctor,还要写assignment

在这里插入图片描述

Unperfect Forwarding

**forward(2) 、forward(move(a)) for进来的时候是右值,但是用这个i再去调用process的时候已经是左值了 **

forward(a) 左值是没有办法调用的

在这里插入图片描述

标准库中有一些散落的forward、move 可以很好地解决这个问题

用标准库的std::forward可以完美地转交

25. 写一个Move aware class

对于move ctor把指针赋值过来,长度也加过来

把原来对象的指针设置为NULL,并且给长度设置为0

注意不要删除对象,是要放到析构里做的

临时对象出了这个函数大括号 析构函数就给他杀了

在这里插入图片描述
在这里插入图片描述

析构函数时,因为被偷的已经是null了,所以不会影响data里的字符串内容

26. Move aware class 对容器的效能测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

关于对于容器,用或者不用move,对于vector影响最大,对于其他容器影响不大。除了对于deque要往里面insert的时候,要找到短的一边推一下。

容器以节点的形式存在,影响不大,它要移动就是真的要一个一个地移动

一个Vector只是由三根指针组成的

在move ctor vector的时候,它只是换了三根指针

copy ctor 是真的一个一个地在交换

在这里插入图片描述

在这里插入图片描述

28. 容器array

在这里插入图片描述

对于数组来说,没有ctor,dtor,所以array也没有这些

29-30. 容器Hashtable、Hashfunction

在这里插入图片描述

特化版本

在这里插入图片描述
在这里插入图片描述

创建hash对象并且()已经完成了操作符重载,相当于就返回了hashcode的结果

在这里插入图片描述

得到hashcode之后,再除以篮子个数,得到的余数就是它挂载哪个bucket上

上面是创建了三个临时对象

下面的是创建一个有名称的对象并调用三次hashcode的计算函数

声明了很多不同的特化版本:

在这里插入图片描述

不同特化的声明以及hash_code的计算方法

在这里插入图片描述

在这里插入图片描述

注意上方的声明都是在functional_hash.h文件中声明的

对于我们自己定义的类,或者一些非基础类,是要在他们自己的.h文件中写好hash的特化版本的

在这里插入图片描述

万用的Hash Function

在这里插入图片描述

在这里插入图片描述

里面还要结合Variadic Templates,并且用到了黄金分割

在这里插入图片描述

在这里插入图片描述

31. Tuple

(Variadic Templates 递归继承 递归组合)

这里讲的是运用

在这里插入图片描述

get<1>(t1) = get<1>(t2)
//可以直接拿tuple的元素做赋值

t1 = t2; 
//也可以整个tuple赋值

cout << t1;
//注意要重载<<

tie(i1, f1, s1) =  t3;
//这三个等于t3里的值
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: c参考手册是一份关于C语言的指南手册,它包含了一系列关于不同版本C语言的详细说明和指导。 c98是C语言的一种早期标准,c03、c11、c14、c17和c20分别代表了C语言的不同版本。这些版本中每一版都会有一些新的特性和改进,学习者可以根据自己所用的C语言版本查找相关的信息。 使用c参考手册,可以帮助开发者和学习者更好地理解、学习和使用C语言。手册中会介绍C语言的语法、数据类型、运算符、控制结构、函数、库函数等主要知识点,并给出实例说明和详细的说明文档。 该参考手册是一个非常有用的工具,无论是初学者还是有经验的开发者都可以从中获取到关键的信息。通过查阅手册,开发者能够解决问题、了解各种函数和语法的用法,并学习如何编写高效、可靠的C语言代码。 总之,c参考手册能够提供给C语言学习者和开发者所需的基本知识和技能,使他们在使用C语言进行编程时更加自信和熟练。无论是在学习、教学还是实际项目开发中,c参考手册都是一个重要的资源。 ### 回答2: c参考手册是一种用于编程语言C的文档,它包含了不同版本的C语言的规范和特性。这些版本包括c98、c03、c11、c14、c17和c20。 C语言是一种通用的计算机编程语言,广泛用于系统级开发、嵌入式系统和高性能应用程序的编写。每个版本的C语言都有不同的规范和特性,为开发人员提供了不同的功能和工具。因此,每个版本都有相应的参考手册,供开发人员查询和使用。 参考手册通常包含了语法、数据类型、函数、库函数和常见编程技巧等方面的信息。它详细介绍了每个版本的C语言的特性和用法,供开发人员参考和使用。开发人员可以从参考手册中找到特定版本的语言规范和相关的函数库,以便更好地进行编程和开发工作。 在进行C语言编程时,参考手册是非常重要的工具,可以帮助开发人员理解和掌握C语言的语法结构和用法。通过查阅参考手册,开发人员可以快速找到所需的信息,并解决编程中遇到的问题。 总之,对于学习和使用C语言开发人员来说,参考手册是必不可少的工具。它为不同版本的C语言提供了规范和特性的详细介绍,帮助开发人员更好地使用和理解C语言。无论是初学者还是有经验的开发人员,都可以从参考手册中获得很多有价值的信息。 ### 回答3: c 参考手册是一本电子文档,包含了关于C语言编程的详细参考信息。它是以CHM格式进行存储的,包含了C 98、C 03、C 11、C 14、C 17和C 20的参考说明书。CHM是一种Microsoft Windows帮助格式,可以方便地浏览和查阅。 C语言是一种广泛应用于编程领域的高级编程语言,具有简洁、高效和强大的特点。C 98是C语言的第一个标准,C 03、C 11、C 14、C 17和C 20是后续版本的标准,它们在语法和功能上有一些差异。 在c 参考手册中,我们可以找到关于C语言语法、变量、数据类型、运算符、流控制、函数、指针、数组、结构体、文件处理等方面的详细说明和示例代码。这些信息帮助程序员更好地了解和掌握C语言的特性和用法。 通过c 参考手册,我们可以详细了解C 98、C 03、C 11、C 14、C 17和C 20版本的差异和新增功能。这有助于程序员根据自己的需求选择合适的C语言版本,并正确地使用新的语言特性。 总之,c 参考手册是C语言程序员的重要工具,它提供了关于C语言的详尽参考信息,帮助程序员解决问题和提高编程技能。对于学习和掌握C语言的人来说,它是一个不可或缺的资源。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值