概述
写在前面
在c++11多线程中,第一次接触到lambda表达式。利用Lambda表达式,可以方便的定义和创建匿名函数
解析
lambda完整的表达形式为:
[ capture ] ( parameters ) mutable -> return-type { statement }
[capture]表示捕获列表,捕获列表一定要出现在lambda表达式开始处,编译器根据[]判断后面是否为lambda函数,捕获列表可以捕获上下文的变量以供lambda函数使用
(parameters)参数列表,与普通函数的参数列表一致,如果不需要参数传递,则可以连括号一同省略。
mutable:mutable修饰,默认情况下,lambda是一个const函数,mutable可以消除其常量性,在使用该修饰符时,参数列表不可省略。
->return-type:返回类型,用跟踪返回类型形式声明函数的返回类型,出于方便,需要返回值的时候可以连同符号->一起省略,此外,在返回类型明确的情况下,也可省略该部分,让编译器对返回类型进行推导。
{statement}:函数体,内容与普通函数一样,不过除了使用参数之外,还可以使用所有捕获的变量。
int main() //各种类型的lambda函数
{
[] {};
int a = 3, b = 4;
[=] {return a + b; };
auto fun1 = [&](int c) {b = a + c; };
auto fun2 = [=, &b](int c)->int {return b += a + c; };
return 0;
}
lambda表达式和函数最大的不同是:lambda可以通过捕捉列表访问上下文中的数据。
捕捉列表可以有多个项组成,其中由逗号隔开,捕捉列表的形式:
[var] | 表示值传递方式捕捉变量var |
[=] | 表示值传递方式捕捉所有父作用域的变量(包括this指针) |
[&var] | 表示引用传递捕捉变量var |
[&] | 表示引用传递捕捉所有父作用域的变量(包括this指针) |
[this] | 表示值传递方式捕捉当前的this指针 |
[=,&a,&b] | 表示以引用传递的方式捕捉变量 a 和 b,而以值传递方式捕捉其他所有的变量 |
[&,a,this] | 表示以值传递的方式捕捉 a 和 this,而以引用传递方式捕捉其他所有变量 |
但是捕捉列表中不允许变量的重复传递,如:
[=, a] | = 已经以值传递方式捕捉了所有的变量,捕捉a重复 |
[&,&this] | & 已经以引用传递方式捕捉了所有变量,捕捉 this 重复 |
栗子
#include <iostream>
#include <string>
#include <thread>
#include <list>
#include <mutex>
using namespace std;
int main()
{
int a = 3, b = 4;
auto Add_1 = [&]()->int {return a + b; };
auto Add_2 = [=] {return a + b; };
cout << Add_1() << endl; //7
cout << Add_2() << endl; //7
return 0;
}
lambda与仿函数
之前在STL中提到过仿函数,我们知道,相对于函数,仿函数具有初始化状态,一般是通过class定义的私有成员,并在对象声明时,对他进行初始化,私有成员函数就变成了仿函数的初始状态,因此一个仿函数对象可以有多个不同初始状态的实例
#include <iostream>
#include <string>
#include <thread>
#include <list>
#include <mutex>
using namespace std;
class rate
{
private:
float _rate;
public:
rate(float a): _rate(a) {}
float operator()(float price)
{
return price * (1 - _rate / 100);
}
};
int main()
{
float tax_rate = 5.5f;
rate changi(tax_rate);
auto changi2 = [tax_rate](float price)->float {return price * (1 - tax_rate / 100); };
float purchased = changi(3369);
float purchased2 = changi2(2899);
return 0;
}
由此栗子可以看出,lambda捕捉了tax_rate变量,仿函数使用tax_rate进行初始化,可以看出,两者除了在语法上有不同之外,lambda和仿函数有着相同的内涵,都可以捕捉一些变量作为初始状态,并接受参数进行运算。
事实上,仿函数使编译器实现lambda的一种方式。
值传递和引用传递的区别
#include <iostream>
#include <string>
#include <thread>
#include <list>
#include <mutex>
using namespace std;
int main()
{
int j = 12;
auto by_val_lambda = [=] {return j + 1; };
auto by_ref_lambda = [&] {return j + 1; };
cout << by_val_lambda() << endl;
cout << by_ref_lambda() << endl;
j++;
cout << by_val_lambda() << endl;
cout << by_ref_lambda() << endl;
return 0;
}
在lambda中值传递和引用传递,第二次调用by_val_lambda函数时,计算的是12+1,在第二次调用by_ref_lambda函数时,计算的是13+1,原因在于:by_val_lambda中,j作为一个常量,在初始化后就不会发生变化,而by_ref_lambda中,j仍然为负父作用域中的值。
lambda的类型
在c++11中的定义上可知,lambda类型被定义为“闭包”的类,每个lambda表达式会产生一个闭包类型的临时变量(右值),因此,严格地讲,lambda函数并非函数指针。不过c++11允许lambda表达式向函数指针的转换,但是前提是lambda函数没有捕获任何变量,且函数指针所示的函数原型,必须跟lambda函数有着相同的调用方式。
#include <iostream>
using namespace std;
int main()
{
int girs = 3, boys = 4;
auto totalChild = [](int x, int y)->int { return x + y; };
typedef int(*allChild)(int x, int y); //自定义数据类型allChild,一个指向函数的指针,指向一个返回型为int,参数为两个int的函数
typedef int(*oneChild)(int x);
allChild p;
p = totalChild; //可以转换
oneChild q;
//q = totalChild; //编译失败!参数必须一致
decltype(totalChild) allPeople = totalChild; // 需通过decltype获得lambda的类型
//decltype(totalChild) totalPeople = p; // 编译失败,指针无法转换lambda
return 0;
}
参考书籍
《深入理解c++11,c++11新特性理解与应用》
最后
以上就是沉默航空为你收集整理的c++11中的lambda表达式的全部内容,希望文章能够帮你解决c++11中的lambda表达式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复