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

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


代替写成下面仿函数这样。

我们直接用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里的值

C++标准11-14相关推荐

  1. VS2010-2015对C++11/14/17特性的支持

    VS2010-2015对C++11/14/17特性的支持 C++11 功能列表 Visual C++ 实现了 C++11 核心语言规范 中的绝大多数功能.许多 C++14 库功能和某些为 C++17 ...

  2. 11.14/11.15 Apache和PHP结合 11.16/11.17 Apache默认虚拟主机

    2019独角兽企业重金招聘Python工程师标准>>> 11.14-11.15 Apache和PHP结合 Apache(httpd)的配置文件:/usr/local/apache2. ...

  3. Effective Modern C++ 第一章 C++11/14/17中的类型推断

    Chapter 1, Deducing Type Item 1: Template type deduction 一些基础知识: 关于左值和右值的一些解释:https://book.2cto.com/ ...

  4. 支持 C++11/14/17 功能(现代 C++

    支持 C++11/14/17 功能(现代 C++) 若要了解有关 Visual Studio 2017 RC 的最新文档,请参阅 Visual Studio 2017 RC 文档. 本文描述了 Vis ...

  5. cpp c++ 11/14/17

    https://mp.weixin.qq.com/s/RYS7YGaeuImcCXzkVhAYJg 我们常用的c++,你对它的标准了解多少呢?本文就带你一探c++11新标准.官网链接:https:// ...

  6. C++11\14\17\20 特性介绍

    C++11 新特性 #01 auto 与 decltype auto: 对于变量,指定要从其初始化器⾃动推导出其类型.⽰例: auto a = 10; // 自动推导 a 为 int auto b = ...

  7. C++11/14/17 新特性总结

    C++11/14/17 新特性总结 initializer_list std::vector<int> vctInts({92, 12, 39, 46, 92, 84, -1, 0, -2 ...

  8. Test on 11/14/2016

    @kaike 第一题太简单我不想说什么 来说第二题. 1.小x的旅行   (travel.pas/c/cpp) [问题描述] 小x大学毕业后,进入了某个公司做了高层管理,他每年的任务就是检查这个公司在 ...

  9. 【晒出你的第83行代码】阿里研究员福贝,用一个小演示程序来解释一下 C++11/14 里的 closure 是可以多么的“爽”...

    为什么80%的码农都做不了架构师?>>>    摘要: 在五四青年节之际,社区发起了来晒晒属于你的"第83行"的活动,活动中邀请业界的大牛.大神们来晒代码或者Re ...

  10. 2018.11.14成立我的博客

    2018.11.14成立我的博客 转载于:https://www.cnblogs.com/zengxx/p/9957509.html

最新文章

  1. java office 集成开发_Office文件格式突变,促使Java和Office更完美集成
  2. “32 位应用已死!”
  3. i.MX6 u-boot 怎么确定板级头文件
  4. 解决标准FPGA资源丰富却浪费的问题
  5. Eclipse 引导阮卓项目 No projects are found to import解
  6. Ubuntu默认不进入图形界面
  7. 第九章 国际化、帮助系统和Qt插件
  8. 3-35Pytorch与visdom
  9. 中国云市场生变:华为云 Q2 份额超 AWS,IaaS+PaaS 迎来整体增长
  10. 计算机vf知识点总结,计算机等级考试二级VF常用函数总结
  11. gom引擎登录器_GOM传奇引擎微端配置详细架设语音教程
  12. java中static代码块_java中静态代码块详解
  13. 超自动化如何提升保险业?
  14. Ubuntu虚拟机实现与主机之间复制粘贴
  15. 64位windows在安装winsdk过程中遇到的问题及解决方案
  16. c语言瑞年条件,C语言如何判断是闰年,闰年判断条件
  17. 英国伦敦国王学院计算机申请容易吗,2020年伦敦国王学院容易申请吗
  18. IOS swift开发——获取设备定位信息
  19. 想自由查看自己网站每个页面流量情况?这个工具可以满足需求!
  20. python 点击按钮 click_selenium+Python(Js处理click失效)

热门文章

  1. prompt和instruct的区别究竟是什么
  2. python crop
  3. AI周报丨全新图像分类方法ViR,性能全面超越ViT;谷歌开源最大视觉模型V-MoE
  4. win11系统 打开Bitlocker加密的分区,输入密码后提示位置不可用“无法访问 参数错误”
  5. java连接海康摄像头_Java实现 海康摄像头抓拍图像
  6. 怎么用PS制作创意撕裂效果?撕裂照片就靠它了
  7. 【旅游】【转载】关于户外运动的个人用品装备
  8. 001仓储物流自动化这行是干嘛的?
  9. 改进建议 计算机组成原理,“计算机组成原理”教学方法的探讨及教学质量的改进...
  10. 数字信号处理1:绪论