-
lambda表达式:无需头文件
lambda表达式是一个可调用的代码单元,可以将其理解为一个未命名的内联函数;
可调用即可以对该对象使用调用运算符。支持调用运算符的对象,包括:重载了调用运算符的类,lambda表达式,函数及函数指针。
以下是lambda表达式的通用写法:
[ 捕获列表 ]( 参数列表 ) -> 返回类型{ 函数体内容 }
例1:[sz](int i)->bool {return sz > i;} 是一个lambda表达式,返回类型是bool值,接收一个参数int i,从外部作用域捕获一个已存在的变量sz。
例2:int(*)(int, int) f = [](int a, int b){return a+b;}; f(1, 2); // f是一个函数指针,它被绑定到 lambda表达式:[](int a, int b){return a+b;} 上,其返回类型是a+b的结果值的类型int, f(1, 2) 返回1 + 2的结果。如果lambda表达式中不显式声明返回类型,lambda表达式将根据函数体中的代码推断出返回类型。如果函数体只含一个return语句,则编译器根据返回值的类型推断lambda表达式的返回类型。若函数体不是仅有一条return语句且未显式声明返回类型,那么函数的返回类型为void。
-
lambda的捕获变量:
捕获变量是外层作用域中,已存在的对象被作为同名参数传递到 lambda 函数体中使用。未声明在参数列表中的、外层作用域中已存在的 变量名,会被编译器自动推断为捕获变量。
例:int sz = 1; auto f = [sz](int i)->bool {return sz > i;}; // 值捕获局部变量sz, sz的值是1。
- 捕获列表的第一个参数可以用于声明捕获变量的传递方式,有引用捕获和值捕获两种:
-
引用捕获:用&表示,此时捕获变量在lambda表达式中的修改将同步改变对应外层作用域中变量的值。
值捕获:用=表示,捕获变量在lambda表达式内的修改 不改变外层变量的值。
- 捕获列表的取值:
-
[]
捕获列表空表示不捕获
[名字列表]
表示默认进行值捕获
[&]
表示引用捕获
[=]
表示值捕获
[&, a, b...]
除a、b...外的捕获是引用捕获
[=, a, b...]
除a、b...外的捕获是值捕获
- 捕获的注意点:
-
1、值捕获是在lambda表达式创建时被拷贝:
捕获变量的初始化发生在lambda表达式被定义之时,在lambda表达式定义的位置,就完成了捕获变量的传参。因此值捕获的变量其值在调用时取的仍旧是lambda表达式初始化时的该变量值。引用捕获由于是对象的引用,其值与对象当前的值一致。
2、值捕获要求变量必须可以被拷贝;
3、若函数返回一个lambda表达式,此lambda表达式不能是引用捕获的,因为引用捕获的局部变量可能不存在;
4、对于一个const变量使用引用捕获要注意不能改变其值。
lambda表达式的其他注意点:
1、lambda表达式可以忽略参数列表和返回类型,但必须永远包含捕获列表和函数体, 例:[]{ statements; }
2、在lambda中忽略括号和参数列表等价于指定一个空参数列表。
3、只能在lambda表达式只有一条返回语句时省略其返回类型:若lambda表达式只有一条return语句,返回类型的声明:->return_type 可以被省略,但一旦lambda表达式有除return之外的语句,省略了返回类型的lambda表达式的返回类型将被编译器自动推断为void。因此只能在lambda表达式只有一条返回语句时省略返回类型。
bind:定义在头文件<functional>中
bind的通常用法:
auto newCallable = bind(callable, arg_list);
bind 函数将一个可调用对象绑定到另一个可调用对象上,作用类似于参数的接口转换器。
bind函数接受一个可调用对象callable和参数列表arg_list作为参数,返回一个新的可调用对象newCallable 。arg_list将作为callable的实参列表,arg_list列表中的元素可以是一个变量也可以是一个占位符。newCallable有几个占位符,newCallable就接收几个实参。实参将按照占位符的数字值标识的顺序传递给callable作为参数。
占位符placeholder:
占位符_n 都定义在命名空间placeholder中:应使用using std::placeholders或using std::placeholders::_1; 在程序中声明。占位符的作用是先占住当前的位置,之后将传入的第n个参数放到这个位置上,n是占位符所标识的数字,如_1将第一个参数放到它所在位置。举例:
-
auto newCallable = bind(add, 6, std::placeholder::1); 中newCallable的第一个参数,会被放到std::placeholder::1的位置,然后得到,bind(add, 6, 参数1) ,bind又将使用参数列表调用add.其结果是调用newCallable(参数1)就是调用add(6, 参数1)。
-
占位符定义在头文件<functional>中。
-
bind参数次序的实例:
设x、y、z是三个实参,那么对于using std::placeholders; auto newCallable = bind(callable, _1, "abc" , _3, _2 ); 调用 newCallable(x, y, z) 相当于调用 callable(x, "abc", z, y) ;
以下示例可说明占位符的次序:
bind的作用与示例:
bind 通过将固定参数写在arg_list中,未知参数使用占位符的方式,完成将接口从接收多个参数转为接受更少的参数的作用。
例:
为完成通过find_if和check_size找出vector<string>中第一个长度大于6的元素,使用bind:
bool check_size(const string, string::size_type sz){
return s.size() >= sz;
}
auto check6 = bind(check_size, std::placeholders::_1, 6); // 占位符 _1 表示占住check_size的第一个参数的位置,之后传递给 _1 的参数,将作为check_size的第一个实参。
find_if(v.begin(), v.end(), check6);
C++primer -lambda表达式与bind
于 2024-02-27 02:38:17 首次发布