本章主要内容:
一,lambda表达式
1.基本概念
2.关于捕获子句
3.常见的捕获方式
二,闭包与std::bind模板
1.什么是闭包
2.std::bind的简介
3.std::bind的用法
三,参考阅读
一,lambda表达式

1.基本概念
lambda表达式是从C++11开始引入的,主要用来定义匿名函数和闭包。lambda表达式可以被当作一个值赋给另一个变量,也可以作为实参传递给其他函数,或者作为其他函数的返回结果,用法类似于前面提到的函数对象和函数指针。如果只是把单个函数拿来传参,lambda表达式的使用方式比函数指针和函数对象更简洁。
lambda表达式可以不指定函数的返回类型,编译器将自动推导该类型。
lambda表达式的完整公式:
[capture_list](parameter_list) mutable -> return_type{ process code };
[](int x, int y){return x<y;} //[]用来标记lambda表达式的开始
[](int x=0, int y=0){return x<y;} //传默认实参x=0,C++14标准开始支持
[]{return true;} //没有参数时,可以省略圆括号()
[](int x, int y)->bool{return x<y;} //显式指定返回值类型,让代码更清晰
注意,lambda表达式中的”[ ]”不一定是空的,里面可以包含捕获子句,捕获子句用来捕获上下文中的变量来提供给lambda表达式使用。
C++代码样例:
Demo1:
#include<iostream>
using namespace std;
int main() {
auto operation = [](int a, int b, string op) -> double {
if (op == "sum") {
return a + b;
}
else {
return (a + b) / 2.0;
}
};
int num1 = 1;
int num2 = 2;
auto sum = operation(num1, num2, "sum");
cout << "Sum = " << sum << endl;
auto avg = operation(num1, num2, "avg");
cout << "Average = " << avg;
return 0;
}
运行结果:
Sum = 3
Average = 1.5
Demo2: lambda与std::for_each结合使用
#include <bits/stdc++.h>
#include <iostream>
using namespace std;
int main()
{
vector<int> vec{ 1, 2, 3, 4, 5 };
for_each(vec.begin(),
vec.end(),
[](int& a) { a *= 2; }
);
for_each(vec.begin(),
vec.end(),
[](int a) { cout << a << " " ; }
);
cout << endl;
return 0;
}
运行结果:
2 4 6 8 10
2.关于捕获子句
捕获子句定义了lambda表达式访问(捕获)表达式以外的参数和变量的方式。
默认的捕获子句有两种即”=”(按值捕获)和”&”(按引用捕获)。
为什么要有捕获子句:
当[ ]中为空时,lambda表达式只能访问lambda表达式中定义的局部实参和局部变量。当[ ]中不为空时,lambda表达式可以访问代码指定作用域中的所有参数和变量。因此,捕获子句的使用扩大了lambda表达式捕获变量的范围。
3.常见的捕获方式
方式一,按值捕获
方括号中包含”=”,指定作用域中变量的值可以传递到lambda表达式,lambda表达式可以使用变量的值,但是不能修改变量的值。
方式二,按引用捕获
方括号中包含”&”,指定作用域中变量的引用可以传递到lambda表达式,lambda表达式既可以使用变量的值,也可以修改变量的值。
方式三,捕获指定的变量
捕获变量和默认捕获子句的操作有些区别:
按值捕获变量:[ ]中直接传变量名,不带”=”。
按引用捕获变量:[ ]中传的是 “&”后面加变量名。
捕获多个变量时可以用逗号分隔,例如:
[=, &counter] //按引用捕获counter,按值捕获其他变量
[&, counter] //按值捕获counter,按引用捕获其他变量
[&, &counter]
[=, &counter, number]
C++代码样例
#include<iostream>
using namespace std;
int main() {
int initial_sum = 100;
auto add_to_sum = [initial_sum](int num) {
return initial_sum + num;
};
int final_sum = add_to_sum(78);
cout << "100 + 78 = " << final_sum;
return 0;
}
100 + 78 = 178
#include <functional>
#include <iostream>
using namespace std;
int main()
{
int i = 3;
int j = 5;
function<int(void)> f1 = [i, j] { return i + j; };
i = 22;
j = 44;
function<int(void)> f2 = [&i, &j] { return i + j; };
cout << f1() << endl;
cout << f2() << endl;
}
8
66
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
class Scale
{
public:
explicit Scale(int scale) : _scale(scale) {}
void ApplyScale(const vector<int>& v) const
{
for_each(v.begin(), v.end(), [this](int n) { cout << n * _scale <<" "; });
cout << endl;
}
private:
int _scale;
};
int main()
{
vector<int> values;
values.push_back(1);
values.push_back(2);
values.push_back(3);
values.push_back(4);
Scale s(3);
s.ApplyScale(values);
}
3 6 9 12
二,闭包与std::bind模板

1.什么是闭包
2.std::bind的简介
3.std::bind的用法
int add(int first, int second)
{
return first + second;
}
std::bind将函数名作为其第一个参数,后面的参数用”_1,_2″这样的占位符来预留,得到一个函数对象add_func。add_func可以像函数一样直接被调用。
auto add_func = std::bind(&add, _1, _2);
add_func(4,5); //4+5, 返回9
auto new_add_func = std::bind(&add, 12, _1);
new_add_func(5); //12+5, 返回17
完整C++代码实现:
#include <iostream>
#include <functional>
using namespace std;
int add(int first, int second)
{
return first + second;
}
int main()
{
auto new_add_func = std::bind(&add, 12, placeholders::_1);
int x = new_add_func(5);
cout << x << endl;
return 0;
}
运行结果:
17
三,参考阅读
《Beginning C++17, 5th Edition》
《深入理解C++11:C++11新特性解析与应用》
《C++高级编程》
https://leimao.github.io/blog/CPP-Closure/
https://thispointer.com/stdbind-tutorial-and-usage-details/
https://www.programiz.com/cpp-programming/lambda-expression
https://learn.microsoft.com/en-us/cpp/cpp/examples-of-lambda-expressions?view=msvc-170
原文始发于微信公众号(程序员与背包客):C/C++开发基础——lambda表达式与std::bind闭包
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/128581.html