这个其实在QT中经常用到,但是之前自己学习的时候也是一知半解的,没有彻底的搞明白,在这里,做一个整理
文章参考:Lambda表达式 | 爱编程的大丙
lambda表达式定义了一个匿名函数,并且可以捕获一定范围内的变量。其语法形式归纳如下:
[capture](params) opt -> ret {body;};
capture是捕获列表,params是参数列表,opt是函数选项,ret是返回值类型,body是函数体。
捕获列表[]: 捕获一定范围内的变量
参数列表(): 和普通函数的参数列表一样,如果没有参数参数列表可以省略不写。
opt 选项, 不需要可以省略
mutable: 可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)auto f2 = [=]()mutable {return a++; }; // ok,其中a是外部捕获的值
exception: 指定函数抛出的异常,如抛出整数类型的异常,可以使用throw();
返回值类型:在C++11中,lambda表达式的返回值是通过返回值后置语法来定义的。C++11中允许省略lambda表达式的返回值,一般情况下,不指定lambda表达式的返回值,编译器会根据return语句自动推导返回值的类型,但需要注意的是labmda表达式不能通过列表初始化自动推导出返回值类型。
auto f1 = []()
{
return {1, 2}; // 基于列表初始化推导返回值,错误
}函数体:函数的实现,这部分不能省略,但函数体可以为空。
关于捕获列表:
[] - 不捕捉任何变量
[&] - 捕获外部作用域中所有变量, 并作为引用在函数体内使用 (按引用捕获)
[=] - 捕获外部作用域中所有变量, 并作为副本在函数体内使用 (按值捕获),拷贝的副本在匿名函数体内部是只读的,不能修改,若修改则会报错,除非使用opt选项为mutable
[=, &foo] - 按值捕获外部作用域中所有变量, 并按照引用捕获外部变量 foo
[bar] - 按值捕获 bar 变量, 同时不捕获其他变量
[&bar] - 按引用捕获 bar 变量, 同时不捕获其他变量
[this] - 捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样的访问权限
如果已经使用了 & 或者 =, 默认添加此选项
例如:
- #include
- #include
- using namespace std;
-
- class Test
- {
- public:
- void output(int x, int y)
- {
- auto x1 = [] {return m_number; }; // error
- auto x2 = [=] {return m_number + x + y; }; // ok
- auto x3 = [&] {return m_number + x + y; }; // ok
- auto x4 = [this] {return m_number; }; // ok
- auto x5 = [this] {return m_number + x + y; }; // error
- auto x6 = [this, x, y] {return m_number + x + y; }; // ok
- auto x7 = [this] {return m_number++; }; // ok
-
-
- int a = 10, b = 20;
- auto f1 = [] {return a; }; // error
- auto f2 = [&] {return a++; }; // ok
- auto f3 = [=] {return a; }; // ok
- auto f4 = [=] {return a++; }; // error
- auto f5 = [a] {return a + b; }; // error
- auto f6 = [a, &b] {return a + (b++); }; // ok
- auto f7 = [=, &b] {return a + (b++); }; // ok
-
- }
- int m_number = 100;
- };
lambda表达式的本质
lambda表达式的类型在C++11中会被看做是一个带operator()的类,即仿函数。
按照C++标准,lambda表达式的operator()默认是const的,一个const成员函数是无法修改成员变量值的。
因为lambda表达式在C++中会被看做是一个仿函数,因此可以使用std::function和std::bind来存储和操作lambda表达式:
- #include
- #include
- using namespace std;
-
- int main(void)
- {
- // 包装可调用函数
- 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;
- cout << f2(200) << endl;
- return 0;
- }
对于没有捕获任何变量的lambda表达式,还可以转换成一个普通的函数指针:
- using func_ptr = int(*)(int);
- // 没有捕获任何外部变量的匿名函数
- func_ptr f = [](int a)
- {
- return a;
- };
- // 函数调用
- f(1314);