C++11中的匿名函数(lambda函数,lambda表达式)

来源:互联网 发布:男 休闲鞋类推荐 知乎 编辑:程序博客网 时间:2024/05/29 18:53

这篇文章是根据维基百科整理来的,原文请看:http://en.wikipedia.org/wiki/Anonymous_function#C.2B.2B

  C++11提供了对匿名函数的支持,称为Lambda函数(也叫Lambda表达式). Lambda表达式具体形式如下:

    [capture](parameters)->return-type{body}

  如果没有参数,空的圆括号()可以省略.返回值也可以省略,如果函数体只由一条return语句组成或返回类型为void的话.形如:

     [capture](parameters){body}

  下面举了几个Lambda函数的例子:      

[](int x, int y) { return x + y; } // 隐式返回类型[](int& x) { ++x; }   // 没有return语句 -> lambda 函数的返回类型是'void'[]() { ++global_x; }  // 没有参数,仅访问某个全局变量[]{ ++global_x; }     // 与上一个相同,省略了()

  可以像下面这样显示指定返回类型:  

[](int x, int y) -> int { int z = x + y; return z; }

  在这个例子中创建了一个临时变量z来存储中间值. 和普通函数一样,这个中间值不会保存到下次调用. 什么也不返回的Lambda函数可以省略返回类型, 而不需要使用 -> void 形式.
  Lambda函数可以引用在它之外声明的变量. 这些变量的集合叫做一个闭包. 闭包被定义在Lambda表达式声明中的方括号[]内. 这个机制允许这些变量被按值或按引用捕获.下面这些例子就是:  

[]        //未定义变量.试图在Lambda内使用任何外部变量都是错误的.[x, &y]   //x 按值捕获, y 按引用捕获.[&]       //用到的任何外部变量都隐式按引用捕获[=]       //用到的任何外部变量都隐式按值捕获[&, x]    //x显式地按值捕获. 其它变量按引用捕获[=, &z]   //z按引用捕获. 其它变量按值捕获

  接下来的两个例子演示了Lambda表达式的用法.  

复制代码
std::vector<int> some_list;int total = 0;for (int i=0;i<5;++i) some_list.push_back(i);std::for_each(begin(some_list), end(some_list), [&total](int x) {    total += x;});
复制代码

  此例计算list中所有元素的总和. 变量total被存为lambda函数闭包的一部分. 因为它是栈变量(局部变量)total的引用,所以可以改变它的值.  

复制代码
std::vector<int> some_list;  int total = 0;  int value = 5;  std::for_each(begin(some_list), end(some_list), [&, value, this](int x)   {    total += x * value * this->some_func();  });
复制代码

  此例中total会存为引用, value则会存一份值拷贝. 对this的捕获比较特殊, 它只能按值捕获. this只有当包含它的最靠近它的函数不是静态成员函数时才能被捕获.对protect和priviate成员来说, 这个lambda函数与创建它的成员函数有相同的访问控制. 如果this被捕获了,不管是显式还隐式的,那么它的类的作用域对Lambda函数就是可见的. 访问this的成员不必使用this->语法,可以直接访问.
  不同编译器的具体实现可以有所不同,但期望的结果是:按引用捕获的任何变量,lambda函数实际存储的应该是这些变量在创建这个lambda函数的函数的栈指针,而不是lambda函数本身栈变量的引用. 不管怎样, 因为大数lambda函数都很小且在局部作用中, 与候选的内联函数很类似, 所以按引用捕获的那些变量不需要额外的存储空间.
  如果一个闭包含有局部变量的引用,在超出创建它的作用域之外的地方被使用的话,这种行为是未定义的!
  lambda函数是一个依赖于实现的函数对象类型,这个类型的名字只有编译器知道. 如果用户想把lambda函数做为一个参数来传递, 那么形参的类型必须是模板类型或者必须能创建一个std::function类似的对象去捕获lambda函数.使用 auto关键字可以帮助存储lambda函数,  

auto my_lambda_func = [&](int x) { /*...*/ };auto my_onheap_lambda_func = new auto([=](int x) { /*...*/ });

  这里有一个例子, 把匿名函数存储在变量,数组或vector中,并把它们当做命名参数来传递 

复制代码
#include<functional>#include<vector>#include<iostream>double eval(std::function<double(double)> f, double x = 2.0){return f(x);}int main(){     std::function<double(double)> f0    = [](double x){return 1;};     auto                          f1    = [](double x){return x;};     decltype(f0)                  fa[3] = {f0,f1,[](double x){return x*x;}};     std::vector<decltype(f0)>     fv    = {f0,f1};     fv.push_back                  ([](double x){return x*x;});     for(int i=0;i<fv.size();i++)  std::cout << fv[i](2.0) << "\n";     for(int i=0;i<3;i++)          std::cout << fa[i](2.0) << "\n";     for(auto &f : fv)             std::cout << f(2.0) << "\n";     for(auto &f : fa)             std::cout << f(2.0) << "\n";     std::cout << eval(f0) << "\n";     std::cout << eval(f1) << "\n";     return 0;}
复制代码

  一个没有指定任何捕获的lambda函数,可以显式转换成一个具有相同声明形式函数指针.所以,像下面这样做是合法的:
 

auto a_lambda_func = [](int x) { /*...*/ };void(*func_ptr)(int) = a_lambda_func;func_ptr(4); //calls the lambda.

 

  

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 微信买票身份核验失败怎么办 买高铁票待核验怎么办 网上购票身份待核验怎么办 b站稿件版权原因怎么办 已离职老板打电话说账有问题怎么办 开到应急刹车道怎么办 自动挡的车刹车失灵怎么办 自动挡的车如果刹车失灵怎么办 手动挡汽车刹车失灵怎么办 车辆没有年检出了交通事故怎么办 跟着大货车闯了红灯怎么办 在万家金服买的电子产品坏了怎么办 汽车被油笔画了怎么办? 挂到别人车跑了怎么办 浪琴手表保修卡掉了怎么办 事故车辆维修和报废怎么办 4.2货车拉缸了怎么办 工作中与同事发生矛盾怎么办 和领导关系闹僵怎么办 内倒窗户卡住了怎么办 支付宝存在安全风险怎么办 地铁车站空调坏了怎么办 面试防汛值班发生灾情你怎么办 怀孕上班路途太远怎么办 硕士错过校招应该怎么办 收银员收多了钱怎么办 商铺贷款批不了怎么办 铁路局的门面乱收房租怎么办 酒店夜审房费多过怎么办 夜审房价录多了怎么办 做工地拿不到钱怎么办 赢了官司拿不到钱怎么办 工地上拿不到钱怎么办 做了工拿不到钱怎么办 高速公路上车没油了怎么办 高铁乘务员年龄大了怎么办 总公司跑路了分公司怎么办 坐车久了耳朵懵怎么办 过完隧道耳朵疼怎么办 护照还在大使馆需要出国怎么办 护照在大使馆不返回怎么办