基本用法
// 语法格式
[capture](params) opt -> ret {body;};
其中 capture
是捕获列表,params
是参数列表,opt
是函数选项,ret
是返回值类型,body
是函数体
- 捕获列表
[]
:捕获一定范围内的变量 - 参数列表
()
:和普通函数的参数列表一样,如果没有参数参数列表可以省略不写 opt
选项, 不需要可以省略mutable
:可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)exception
:指定函数抛出的异常,如抛出整数类型的异常,可以使用throw()
;
- 返回值类型:在 C++11 中,
lambda
表达式的返回值是通过返回值后置语法来定义的 - 函数体:函数的实现,这部分不能省略,但函数体可以为空
捕获列表
[]
不捕捉任何变量[&]
捕获外部作用域中所有变量, 并作为引用在函数体内使用 (按引用捕获)[=]
捕获外部作用域中所有变量, 并作为副本在函数体内使用 (按值捕获)- 拷贝的副本在匿名函数体内部是只读的
[=, &foo]
按值捕获外部作用域中所有变量, 并按照引用捕获外部变量foo
[bar]
按值捕获bar
变量, 同时不捕获其他变量[&bar]
按引用捕获bar
变量, 同时不捕获其他变量[this]
捕获当前类中的this
指针- 这个是在类中定义函数时的捕获,不管
[this], [=], [&]
都可访问成员属性和函数,并且修改成员变量的值 - 如果是在类外使用
&
或者=
并且创建了类对象,也会捕捉到,=
是只读状态不可修改成员变量值,&
修改会引起成员变量值改变
- 这个是在类中定义函数时的捕获,不管
// 执行体后面加 () 就是表示函数的调用
class Test {
public:
void output(int x, int y)
{
auto x1 = [=] {return a + x + y; }(); // ok
auto x2 = [this] {return a; }(); // ok
auto x3 = [this] {return a + x + y; }(); // 错误,因为没有捕获 x,y
auto x4 = [this, x, y] {return a + x + y; }(); // ok
auto x5 = [this] {return a++; }(); // ok,并且会改变 a 的值
auto x6 = [x] {return x++; }(); // 错误,按值传递是只读状态
auto x6 = [x] mutable {return x++; }(); // ok
}
int a = 100;
};
void func(int x, int y) {
int b = 9;
[b]()mutable {
b++;
cout << b << endl;
}();
cout << "b: " << b << endl;
}
// 这个 b 外部输出为 9,lambda 中输出 10,因为按值传递,加上 mutable 具有改变的权限
// 但是不改变原本的值,只是当作副本的修改
// 调用传的参数可以直接使用 ()
void func(int x, int y) {
int b = 9;
[](int b)mutable {
b++;
cout << b << endl;
}(b);
cout << "b: " << b << endl;
}
返回值
// 完整的lambda表达式定义
auto f = [](int a) -> int {
return a + 10;
};
// 忽略返回值的 lambda 表达式定义
// 这是因为编辑器可以自动类型推导
auto f = [](int a) {
return a + 10;
};
// 错误,不能推导出返回值类型
// 因为无法确定准确的类型,这可以是数组,类....
auto f1 = []() {
return {1, 2}; // 基于列表初始化推导返回值,错误
}
函数本质
lambda
表达式的类型在 C++11 中会被看做是一个带operator()
的类,即仿函数- 按照 C++标准,
lambda
表达式的operator()
默认是const
的,一个const
成员函数是无法修改成员变量值的 mutable
选项的作用就在于取消operator()
的const
属性
使用
std::function
和std::bind
来存储和操作lambda
表达式
// 因为本质是一个仿函数
int main()
{
// 包装可调用函数
std::function<int(int)> f1 = [=](int a) {
return a;
};
// 绑定可调用函数
std::function<int(int)> f2 = bind([=](int a) {
return a;
}, placeholders::_1);
// 函数调用
cout << f1(100) << endl; // 100
cout << f2(200) << endl; // 200
return 0;
}
对于没有捕获任何变量的
lambda
表达式,可以转换成一个普通的函数指针
using func_ptr = int(*)(int);
// 没有捕获任何外部变量的匿名函数
func_ptr f = [](int a) {
return a;
};
// 函数调用
f(10);
// 错误,因为不能捕获外部变量
using func_ptr = int(*)(int);
// 没有捕获任何外部变量的匿名函数
func_ptr f = [=](int a) {
return a;
};
// 函数调用
f(10);
说明:本文是在 https://subingwen.cn/ 学习过程中的总结,这个 up 主 B 站讲得很好 !!