C++11(二) 革新:引用折叠与lambda表达式

C++11(二) 革新:引用折叠与lambda表达式 目录前言移动构造和移动赋值引用折叠完美转发lambda表达式语法捕捉列表隐式捕捉隐式值捕捉隐式引用捕捉混合捕捉原理前言接上一篇C11博客的内容继续编写移动构造和移动赋值左值会走上面这个右值会走下面这个这里只有鉴定你的属性是左值才能移动你右值引用里面的资源移动构造和移动赋值与拷贝构造和拷贝赋值的核心区别只有进行深拷贝的类才考虑移动构造和移动赋值左值在这里就得老老实实地拷贝因为都是一些持续存在的值右值都是一些即将销毁的值(临时对象匿名对象等)里面的成员不能进行修改就可以将资源进行掠夺右值引用的属性是左值左值引用是直接起作用传值传参要拷贝传值返回要拷贝传引用传参传引用返回不用拷贝因为返回的是别名形参是实参的别名右值引用是依靠移动语义(移动构造移动赋值)来起作用他把右值引用给区分出来当你要进行右值拷贝的时候移动其资源不管怎么样只要我们写了移动构造和移动赋值传值返回直接接收和先定义对象再接收都没有多大区别这才是保障这里使用右值引用会更高效这里就说明提效了左值插入拷贝构造代价更高右值移动构造的代价更低引用折叠后来的语法喜欢用using去替代typedef引用折叠只要有一个左值引用都是左值引用函数模板的特点是实参传给形参去推出T的类型这里推成左右值都可以折叠只要我写了T不管怎么样都是左值引用传左值是左值引用传右值是右值引用这里是万能引用传左值就是左值传右值就是右值只要是右值都没有折叠就只是int传的是左值就是左值引用完美转发这个不是万能引用因为是类模板的一个成员函数这个T不是通过实参传形参推的而是类模板实例化的时候就实例化的所以就出现了完美转发forward底层的核心原理还是强制类型转换但是与move不同move只能转成右值如下图函数中需要将t值再调用一遍的如果不加入完美转发就会都是左值属性因为不管是左值引用还是右值引用值的本身都是左值属性打印出来的就全是左值引用如果使用了完美转发则可以保持t左值引用的左值引用返回右值引用的右值引用返回完美转发forward本质是⼀个函数模板他主要还是通过引用折叠的方式实现下面示例中传递给Function的实参是右值T被推导为int没有折叠forward内部t被强转为右值引用返回传递给Function的实参是左值T被推导为int引用折叠为左值引用forward内部t被强转为左值引用返回。int main() { // 10是右值推导出T为int模板实例化为void Function(int t) Function(10); // 右值 int a; // a是左值推导出T为int引⽤折叠模板实例化为void Function(int t) Function(a); // 左值 // std::move(a)是右值推导出T为int模板实例化为void Function(int t) Function(std::move(a)); // 右值 const int b 8; // a是左值推导出T为const int引⽤折叠模板实例化为void Function(const intt) Function(b); // const 左值 // std::move(b)右值推导出T为const int模板实例化为void Function(const intt) Function(std::move(b)); // const 右值 return 0; }lambda表达式语法本质是一个匿名函数对象跟普通函数不同的是它可以定义在函数内部参数为空可以省略捕捉为空也不能省略这里返回值部分可以省略可以通过返回对象自动推导写上的话更具有可读性函数体不可以省略相比于仿函数的话lambda表达式需要实现的轻和少(如比大小仿函数需要实现的就很多如一个大小需要实现2个仿函数)lambda不需要取名字因为本身就是匿名函数对象捕捉列表lambda表达式中默认只能用lambda函数体和参数中的变量如果想用外层作用域中的变量就需要进行捕捉lambda表达时是可以写在全局的全局就不需要捕捉必须为空局部的静态和全局变量不能捕捉也不需要捕捉传值捕捉过来的变量是不可以修改的就跟被const修饰了一样是不可以修改的如果想要修改也是可以但是这里的不会影响外面的值因为传值捕捉始终是拷贝隐式捕捉隐式值捕捉用了哪些就捕捉哪些变量隐式引用捕捉用了哪些变量就捕捉哪些变量混合捕捉原理范围for的底层是迭代器lambda底层是仿函数对象捕捉到的变量变成仿函数的成员变量