目录
[Part1. Lambda表达式捕获机制详解](#Part1. Lambda表达式捕获机制详解)
[Part1.1. 值捕获基础特性](#Part1.1. 值捕获基础特性)
[Part1.2. 捕获简写语法](#Part1.2. 捕获简写语法)
[Part1.3. mutable关键字](#Part1.3. mutable关键字)
[Part1.4. lambda底层原理](#Part1.4. lambda底层原理)
[Part2. C++11 类的六大默认成员函数](#Part2. C++11 类的六大默认成员函数)
[Part2.1. 六大默认函数](#Part2.1. 六大默认函数)
[Part2.2. C++11规则](#Part2.2. C++11规则)
[Part2.3. 类型分类](#Part2.3. 类型分类)
[Part2.4. = default关键字](#Part2.4. = default关键字)
[Part3. std::function 函数包装器](#Part3. std::function 函数包装器)
[Part3.1. 作用](#Part3.1. 作用)
[Part3.2. 基础语法](#Part3.2. 基础语法)
[Part3.3. 包装类成员函数](#Part3.3. 包装类成员函数)
[Part3.4. 调用规则](#Part3.4. 调用规则)
[Part3.5. 包装器与逆波兰表达式](#Part3.5. 包装器与逆波兰表达式)
[Part4. std::bind 参数绑定工具](#Part4. std::bind 参数绑定工具)
[Part4.1. 核心能力](#Part4.1. 核心能力)
[Part4.2. 占位符规则](#Part4.2. 占位符规则)
[Part4.3. bind 结合function处理成员函数](#Part4.3. bind 结合function处理成员函数)
[Part5. 结语](#Part5. 结语)
前言
C++11包装器,lambda表达式以及bind的知识是非常重要的。在项目实践,算法题的实现中都有所体现,我们来看看吧。
let's go!!!!!!!!
Part1. Lambda表达式捕获机制详解
Part1.1. 值捕获基础特性
cppint a = 0; int b = 1; auto f = [a, &b](int x) { a++; b += x; }; //[a]:值捕获,仅拷贝外部变量,lambda内部修改的只是副本,不会影响原始变量。 //[&b]:引用捕获,直接绑定外部原始变量,内部修改会作用于外部。 //重点:同一个变量不能同时捕获两次(既值捕获又引用捕获)。
Part1.2. 捕获简写语法
<1> =:全部值捕获。函数体内出现的外部变量,自动以值拷贝捕获;
<2> \&:全部引用捕获。函数体内出现的外部变量,自动以引用捕获;
<3> =, \&a, \&b:默认值捕获,单独指定a、b采用引用捕获;
<4> \&, a, b:默认引用捕获,单独指定a、b采用值捕获。
注意:lambda不能递归。因为lambda类型无法提前声明,无法在捕获列表内引用自身。
Part1.3. mutable关键字
cppauto f = [a](int x) mutable { a++; }; //值捕获得到的成员变量,默认是const属性,不允许修改; //添加mutable后,取消const限制,允许修改捕获的副本。 //再次强调:修改的依旧是拷贝副本,无法改变外部原始变量。
Part1.4. lambda底层原理
Lambda不是语法糖,编译器会自动生成一个匿名仿函数类:
<1> 捕获的外部变量,会变成仿函数类的成员变量;
<2> 参数列表、函数体对应仿函数的operator();
<3> 返回值类型由编译器自动推导,也可以显式-> Type指定。
Part2. C++11 类的六大默认成员函数
Part2.1. 六大默认函数
<1> 默认构造函数
<2> 拷贝构造函数
<3> 拷贝赋值运算符
<4> 移动构造函数
<5> 移动赋值运算符
<6> 析构函数
Part2.2. C++11规则
如果自己没有手动实现,编译器自动生成默认版本。
一旦手动实现其中某一个,会影响其余默认函数的隐式生成。
Part2.3. 类型分类
<1> 内置类型成员:默认构造有时会初始化;
<2> 自定义类成员:调用自身默认构造。
Part2.4. = default关键字
cppPerson(Person&& p) = default; //强制让编译器生成默认版本的移动构造函数,即便你已经手动编写了其他构造函数。 //补充:= delete 则是显式删除函数,禁止调用。
Part3. std::function 函数包装器
头文件:#include <functional>
Part3.1. 作用
统一包装任何可调用对象:普通函数、函数指针、lambda、仿函数、类成员函数;
提供统一的类型,能够存放在容器(map/vector)中,实现回调管理。
Part3.2. 基础语法
cpp// 模板格式:function<返回类型(参数类型列表)> std::function<int(int,int)> f; // 1.包装普通函数 int add(int a,int b){return a+b;} f = add; // 2.包装lambda表达式 f = [](int a,int b){return a+b;};
Part3.3. 包装类成员函数
成员函数隐藏参数this,使用function包装分两种情况:
cpp<1> 静态成员函数 静态成员不存在this,直接正常包装: struct A{ static int fun(int a,int b){ return a-b; } }; std::function<int(int,int)> f = A::fun; <2> 非静态成员函数 必须额外传入对象(对象/对象指针),对应隐式this参数: struct A{ int fun(int a,int b){ return a-b; } }; A a1; // 第一种写法:绑定对象实例 std::function<int(int,int)> f = std::bind(&A::fun, a1, _1, _2); // 第二种:绑定对象指针 std::function<int(int,int)> f = std::bind(&A::fun, &a1, _1, _2); 参数占位符 _1、_2、_3 定义在命名空间 std::placeholders。
Part3.4. 调用规则
int res = f(10,20);
调用时传入参数,占位符_1匹配第一个实参、_2匹配第二个实参。
Part3.5. 包装器与逆波兰表达式
cppclass Solution { public: int evalRPN(vector<string>& tokens) { stack<int> aaa; map<string,function<int(int,int)>> F={ {"+",[](int a,int b){return a+b;}}, {"-",[](int a,int b){return a-b;}}, {"/",[](int a,int b){return a/b;}}, {"*",[](int a,int b){return a*b;}} };//将包装器与容器结合 for(int i=0;i<tokens.size();i++) { if(F.find(tokens[i])==F.end()) { aaa.push(stoi(tokens[i])); } else { int a=aaa.top(); aaa.pop(); int b=aaa.top(); aaa.pop(); aaa.push(F[tokens[i]](b,a)); } } return aaa.top(); } };
Part4. std::bind 参数绑定工具
头文件:#include <functional>
Part4.1. 核心能力
<1> 固定函数某些参数;
<2> 重新调整参数顺序;
<3> 配合std::function包装成员函数。
Part4.2. 占位符规则
cppstd::placeholders::_1、_2...... //含义:代表调用bind返回的函数时,传入的第N个参数。 示例: using namespace std::placeholders; int sub(int a,int b){ return a - b; } // 固定第一个参数为100,剩余参数由调用时传入 auto sub1 = bind(sub, 100, _1); sub1(5); // 等价 sub(100,5) → 95 // 调换参数顺序 auto sub2 = bind(sub, _2, _1); sub2(10,5); // 等价 sub(5,10) → -5
Part4.3. bind 结合function处理成员函数
cppstruct A{ int calc(int x,int y){ return x+y; } }; A obj; // bind绑定成员函数 + 对象实例 + 占位符 function<int(int,int)> f = bind(&A::calc, obj, _1, _2);原理:
bind返回一个可调用对象;
std::function可以接收该对象进行存储;
非静态成员函数依赖this,bind会捕获对象,后续调用不需要再传递实例。
Part5. 结语
这篇文章我们认识到了C++11相关知识,接下来,小编还会带来C++异常处理的知识,敬请期待~
最后,祝大家可以:春风得意马蹄疾,一日看尽长安花!最后的最后,要是觉得本文还可以的话,可以点点赞,关注小编一波 ,谢谢大家!~

