概述:lambda表达式使用及说明
[toc]
lambda表达式说明
lambda表达式的结构如下所示:
1 auto func = [capture] (params) opt -> ret { func_body; };
其中 func 是可以当作 lambda 表达式的名字,作为一个函数使用,capture 是捕获列表,params 是参数表,opt: 不需要可以省略。 (mutable: 可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)exception: 指定函数抛出的异常,如抛出整数类型的异常,可以使用 throw ()), ret 是返回值类型,func_body 是函数体。
1 2 auto f = [](int a) -> int { return a + 1 ; }; std::cout << f (1 ) << std::endl;
使用 lambda 表达式捕获列表
lambda 表达式还可以通过捕获列表捕获一定范围内的变量:
[] 不捕获任何变量。
[&] 捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。
[=] 捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。
[=,&foo] 按值捕获外部作用域中所有变量,并按引用捕获 foo 变量。
[bar] 按值捕获 bar 变量,同时不捕获其他变量。
[this] 捕获当前类中的 this 指针,让 lambda 表达式拥有和当前类成员函数同样的访问权限。如果已经使用了 & 或者 =,就默认添加此选项。捕获 this 的目的是可以在 lamda 中使用当前类的成员函数和成员变量。
捕获列表使用实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <iostream> #include <functional> using namespace std;class lambdaTest {public : void output (int x, int y) { auto x2 = [=] {return m_number + x + y; }; auto x4 = [&] {return m_number + x + y; }; auto x5 = [this ] {return m_number; }; auto x7 = [this , x, y] {return m_number + x + y; }; } int m_number = 100 ; };int main () { lambdaTest test; test.output (1 ,2 ); }
函数
是否可读
是否可修改
说明
x1
❌
❌
错误,没有捕获外部变量,不能使用任何外部变量
x2
✔️
❌
正确,值传递,可以访问所有外部变量
x3
✔️
❌
错误,值传递,右值可读不可修改
x4
✔️
✔️
正确,引用传递,可读可修改
x5
✔️ this指针的成员变量可读 ❌ 其他变量不可读
✔️ this指针的成员可写 ❌ 其他变量不可写
正确,捕获this指针,可访问this指针的成员
x6
同 x5
同 x5
错误,捕获 this 指针,x
和 y
不是其成员变量,不可访问
x7
✔️ 值传递三个变量,均可读
✔️ this指针成员可修改 ❌ x 和 y 不可修改
正确,捕获 this 指针,x,y
返回值
lambda表达式的返回值通过 ‘->’ 传递,如下所示:
1 2 3 auto add = [](int x, int y) -> int { return x + y; };
如上所示的返回类型还可以使用 decltype
推导返回类型:
decltype
是一个 C++ 关键字,它用于在编译时推断表达式的类型。这在编写通用代码时非常有用,特别是在使用 C++11 引入的 auto
关键字和范围 for 循环时。
1 2 3 auto add = [](int x, int y) -> decltype (x+y) { return x + y; };
说明:decltype(a + b)
推导了 a + b
的结果类型,并将该类型作为 lambda 函数的返回类型。
甚至,从 C++14 开始,还可以使用更简洁的方式来推导 lambda 函数的返回类型,即使用 auto
关键字。例如:
1 auto myLambda = [](int a, int b) -> auto { return a + b; };
需要注意的是,使用 auto
推导返回类型的 lambda 函数在某些情况下可能会引发歧义。例如,如果你在 lambda 表达式中返回一个嵌套类型(如 std::pair
),auto
可能会被推导为 std::pair
,而不是你期望的嵌套类型的具体类型。在这种情况下,使用 decltype
可以更明确地指定返回类型。
其他关键字
使用 lambda 表达式捕获列表捕获外部变量,如果希望去修改按值捕获的外部变量,那么应该如何处理呢?这就需要使用 mutable 选项,被mutable修改是lambda表达式就算没有参数也要写明参数列表,并且可以去掉按值捕获的外部变量的只读(const)属性。
mutable
1 2 3 int a = 0 ;auto f1 = [=] {return a++; }; auto f2 = [=]()mutable {return a++; };
💁♂️ 注意:mutable 只是允许在函数内部修改值而已,作用域仅限于 lambda 函数内部,参考以下代码及输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 void lambdaFunc () { auto add1 = [](int x, int y) -> int { return x + y; }; auto add2 = [](int x, int y) -> decltype (x + y) { return x + y; }; auto add3 = [](int a, int b) -> auto { return a + b; }; auto modify_add = [](int a, int b) mutable -> auto { a = 3 ; return a + b; }; auto value_modify_add = [=](int a, int b) mutable -> auto { a = 4 ; return a + b; }; auto refrence_modify_add = [&](int a, int b) mutable -> auto { a = 5 ; return a + b; }; auto refrence_modify_add_byRef = [&](int & a, int b) mutable -> auto { a = 6 ; return a + b; }; int x = 2 , y = 2 ; cout << "add1:" << add1 (x, y) << endl; cout << "add2:" << add2 (x, y) << endl; cout << "add3:" << add3 (x, y) << endl; cout << "modify_add:" << value_modify_add (x, y) << endl; cout << "x=" << x << endl; cout << "value_modify_add:" << value_modify_add (x, y) << endl; cout << "x=" << x << endl; cout << "value_modify_add:" << refrence_modify_add (x, y) << endl; cout << "x=" << x << endl; cout << "refrence_modify_add_byRef:" << refrence_modify_add_byRef (x, y) << endl; cout << "x=" << x << endl; }
关于为什么通过值拷贝的方式捕获的外部变量是只读的:
lambda表达式的类型在C11中会被看做是一个带 operator()
的类,即仿函数。
按照C 标准,lambda表达式的 operator()
默认是 const
的,一个 const
成员函数是无法修改成员变量值的。
mutable
选项的作用就在于取消 operator ()
的 const
属性。
因为 lambda 表达式在 C++ 中会被看做是一个仿函数,因此可以使用std::function和std::bind
来存储和操作lambda表达式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void testLambdawithfunction () { std::function<int (int )> f1 = [](int a) {return a; }; std::function<int (int )> f2 = bind ([](int a) {return a; }, placeholders::_1); std::function<int (int &, int )> f3 = [](int & a, int b) { a = 3 ; return a + b; }; std::function<int (int &, int )> f4 = bind ([](int & a, int b) { a = 4 ; return a + b; }, std::placeholders::_1, std::placeholders::_2); int x = 2 , y = 2 ; cout << "f1(100)" << f1 (100 ) << endl; cout << "f2(200)" << f2 (200 ) << endl; cout << "f3(x, y)" << f3 (x, y) << endl; cout << "x=" << x << endl; cout << "f3(x, y)" << f4 (x, y) << endl; cout << "x=" << x << endl; }
对于没有捕获任何变量的 lambda 表达式,还可以转换成一个普通的函数指针:
1 2 3 4 5 6 7 8 9 using func_ptr = int (*)(int ); func_ptr f = [](int a) { return a; };f (1314 );
参考文章