Lambda函数

C++11新增了lambda函数,其基本格式如下
 [捕捉列表] (参数) mutable -> 返回值类型 {函数体}
说明
  • []是lambda的引出符,捕捉列表能够捕捉上下文中的变量,来供lambda函数使用:
    [var] 表示以值传递方式捕捉变量var
    [=] 表示值传递捕捉所有父作用域变量
    [&var] 表示以引用传递方式捕捉变量var
    [&] 表示引用传递捕捉所有父作用域变量
    [this] 表示值传递方式捕捉当前的this指针
       还有一些组合:
    [=,&a] 表示以引用传递方式捕捉a,值传递方式捕捉其他变量
       注意:
       捕捉列表不允许变量重复传递,如:[=,a]、[&,&this],会引起编译时期的错误
  • 参数列表与普通函数的参数列表一致。如果不需要传递参数,可以联连同()一同【省略】。
  • mutable 可以取消Lambda的常量属性,因为Lambda默认是const属性;multable仅仅是让Lamdba函数体修改值传递的变量,但是修改后并不会影响外部的变量。
  • ->返回类型如果是void时,可以连->一起【省略】,如果返回类型很明确,可以省略,让编译器自动推倒类型。
  • 函数体和普通函数一样,除了可以使用参数之外,还可以使用捕获的变量。
最简单的Lambda函数:
 []{}
实例:
 int main(int argc, char* argv[])
{
int a = , b = ;
auto total = [](int x, int y)->int {return x + y; }; //接受两个参数
cout << total(a, b)<<endl; //
auto fun1 = [=] {return a + b; }; //值传递捕捉父作用域变量
cout << fun1() << endl; //
auto fun2 = [&](int c) {b = a + c; a = ; }; //省略了返回值类型,引用捕获所有
fun2(); //1 8
cout << a <<" "<< b << endl;
a = ; b = ; //被修改后,重新赋值
auto fun3 = [=, &b](int c) mutable {b = a + c; a = ; }; //以值传递捕捉的变量,在函数体里如果要修改,要加mutaple,因为默认const修饰
fun3();
cout << a << " " <<b<< endl; //5,8
a = ; b = ; //被修改后,重新赋值
auto fun4 = [=](int x, int y) mutable->int {a += x; b += y; return a + b; };
int t = fun4(, );
cout << t << endl; //
cout << a <<" "<< b << endl; //5 7
return ;
}

  块作用域以外的Lambda函数捕捉列表必须为空,因此这样的函数除了语法上的不同,和普通函数区别不大。

  块作用域以内的Lambda函数仅能捕捉块作用域以内的自动变量,捕捉任何非此作用域或非自动变量(静态变量),都会引起编译器报错。
  改为引用依旧会报错。

Lambda函数与仿函数的关系

  在C++11之前,STL中的一些算法需要使用一种函数对象---仿函数(functor);其本质是重新定义和成员函数operator(),使其使用上很像普通函数,其实,细心的我们已经发现,Lambda函数与仿函数似乎有一些默契。
如下例子:折扣
 class Price
{
private:
float _rate;
public:
Price(float rate):_rate(rate){}
float operator()(float price)
{
return price*( - _rate / );
}
}; int main(int argc, char* argv[])
{
float rate=5.5f; Price c1(rate);
auto c2 = [rate](float price)->float {return price*( - rate / ); }; float p1 = c1(); //仿函数
float p2 = c2(); //Lambda函数 return ;
}
  仿函数以rate初始化,Lambda捕捉rate变量,参数传递上,两者一致。
事实上,仿函数就是实现Lambda函数一种方式,编译器通常会把Lambda函数转换为一个放函数对象,但是仿函数的语法却给我们带来了很大的便捷。
在C++11中,Lambda函数被广泛使用,很多仿函数被取代。

Lambda与static inline函数

  Lambda函数可以省略外部声明的static inline函数,其相当于一个局部函数。局部函数仅属于父作用域,
比起外部的static inline函数,或者是自定义的宏,Lambda函数并没有实际运行时的性能优势(但也不会差),但是Lambda函数可读性更好。
父函数结束后,该Lambda函数就不再可用了,不会污染任何名字空间。

关于值传递捕捉和mutable

  上面提到过mutable 可以取消Lambda的常量属性,如果值传递想要在函数域内修改就要加mutable
先看一个例子:
 int main(int argc, char* argv[])
{
int j = ;
auto by_val = [=] {return j + ; };
auto by_ref = [&] {return j + ; };
cout << by_val() << endl; //
cout << by_ref() << endl; //
j++;
cout << by_val() << endl; //
cout << by_ref() << endl; //
return ;
}
  上面的例子,j++了之后调用值传递结果依旧是12,原因是,值传递j被视为一个常量,一旦初始化,就不会再修改(可以认为是一个和父作用域中j同名的常量),而再引用捕捉中,j仍然是父作用域中的值。
  其实一个值传递的的Lambda转换为放函数后,会成为一个class的常量成员函数,
代码基本如下:
 class const_val_lambda
{
public:
const_val_lambda(int v):val(v){}
public:
void operator()()const { val = ; } //报错
private:
int val;
};
  但是使用引用的方式不会报错,因为不会改变引用本身,只会改变引用的值
  准确地讲,现有C++11标准中的lambda等价的是有常量operatorO的仿函数。因此在使用捕捉列表的时候必须注意,按值传递方式捕捉的变量是lambda函数中不可更改的常量。标准这么设计可能是源自早期STL算法一些设计上的缺陷(对仿函数没有做限制,从而导致一些设计不算特别良好的算法出错)。而更一般地讲,这样的设计有其合理性,改变从上下文中拷贝而来的临时变量通常不具有任何意义。绝大多数时候,临时变量只是用于lambda函数的输入,如果需要输出结果到上下文,我们可以使用引用,或者通过让lambda函数返回值来实现。此外,lambda函数的mutable修饰符可以消除其常量性,不过这实际上只是提供了一种语法上的可能性,现实中应该没有多少需要使用mutable的lambda函数的地方。大多数时候,我们使用默认版本的(非mutable)的lambda函数也就足够了。

Lambda函数与函数指针

  Lambda函数并不是简单的函数指针类型,或者自定义类型;每个Lambda函数会产生一个闭包类型的临时对象(右值)。但是C++11允许Lambda函数向函数指针的转换,前提是:
    Lambda没有捕捉任何变量
    函数指针所示的函数原型,必须和Lambda有相同的调用方式
 int main(int argc, char* argv[])
{
int a = , b = ; auto total = [](int x, int y)->int {return x + y; };
typedef int(*all)(int x, int y);
typedef int(*one)(int x); all p;
p = total;
one q;
q = total; //报错,参数不一致 decltype(total) all_1 = total;
decltype(total) all_2 = p; //报错,指针无法转换为Lambda return ;
}

Lambda与STL

  从C++11开始,Lambda被广泛用在STL中,比如foreach。与函数指针比起来,函数指针有巨大的缺陷:1.函数定义在别处,阅读起来很困难;2.使用函数指针,很可能导致编译器不对其进行inline优化,循环次数太多时,函数指针和Lambda比起来性能差距太大。函数2指针不能应用在一些运行时才能决定的状态,在没有C++11时,只能用仿函数。使得学习STL算法的代价大大降低。
  但是Lambda并不是仿函数的完全代替者。由Lambda的捕捉列表的限制造成的,仅能捕捉副作用域的变量。放函数具有天生跨作用域共享的特征。

C++11 Lambda函数的更多相关文章

  1. C++11—lambda函数

    [1]lambda表达式语法定义 lambda表达式的语法定义如下: [capture] (parameters) mutable ->return-type {statement}; (1) ...

  2. C++11 lambda函数符

    #include<iostream> #include<vector> #include<algorithm> #include<cmath> #inc ...

  3. C++11新特性:Lambda函数(匿名函数)

    声明:本文参考了Alex Allain的文章http://www.cprogramming.com/c++11/c++11-lambda-closures.html 加入了自己的理解,不是简单的翻译 ...

  4. 【C++11】新特性——Lambda函数

    本篇文章由:http://www.sollyu.com/c11-new-lambda-function/ 文章列表 本文章为系列文章 [C++11]新特性--auto的使用 http://www.so ...

  5. 初窥c++11:lambda函数及其用法

    转载于:点击打开链接 为什么需要lambda函数 匿名函数是许多编程语言都支持的概念,有函数体,没有函数名.1958年,lisp首先采用匿名函数,匿名函数最常用的是作为回调函数的值.正因为有这样的需求 ...

  6. C++11 Lambda表达式(匿名函数)

    http://www.cnblogs.com/RainyBear/p/5733399.html http://blog.163.com/lvan100@yeah/blog/static/6811721 ...

  7. python lambda函数详细解析(面试经常遇到)

    1 作用:通常是用来在python中创建匿名函数的 2 格式: lambda 参数[,参数] : 表达式 3 注意: (1)lambda定义的是单行函数, 如果需要复杂的函数,应该定义普通函数 (2) ...

  8. python之Lambda函数---笔记

    <Python3 程序开发指南> Lambda函数,是一个匿名函数,创建语法: lambda parameters:express parameters:可选,如果提供,通常是逗号分隔的变 ...

  9. C++11 lambda 表达式

    C++11 新增了很多特性,lambda 表达式是其中之一,如果你想了解的 C++11 完整特性,建议去这里,这里,这里,还有这里看看.本文作为 5 月的最后一篇博客,将介绍 C++11 的 lamb ...

随机推荐

  1. 843. n-皇后问题(dfs+输出各种情况)

    n-皇后问题是指将 n 个皇后放在 n∗n 的国际象棋棋盘上,使得皇后不能相互攻击到,即任意两个皇后都不能处于同一行.同一列或同一斜线上. 现在给定整数n,请你输出所有的满足条件的棋子摆法. 输入格式 ...

  2. adworld MISC002 | Linux的挂载文件系统的运用

    EXT3是第三代扩展文件系统(英语:Third extended filesystem,缩写为ext3),是一个日志文件系统,常用于Linux操作系统. Plan 1: 直接将附件使用mount命令挂 ...

  3. MapReduce自定义排序器不生效一个可能的原因

    有问题的代码: package com.mytq.weather; import org.apache.hadoop.io.WritableComparable; import org.apache. ...

  4. 高通量计算框架HTCondor(六)——拾遗

    目录 1. 正文 1.1. 一些问题 1.2. 使用建议 2. 相关 1. 正文 1.1. 一些问题 如果真正要将HTCondor高通量计算产品化还需要很多工作要做,HTCondor并没有GUI界面, ...

  5. Java Set集合的详解

    一,Set Set:注重独一无二的性质,该体系集合可以知道某物是否已近存在于集合中,不会存储重复的元素 用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复. 对象的相等性 引用到堆上同一个对象 ...

  6. cookie 与 session区别

    cookie 与 session 是网页开发中常用的信息存储方式.Cookie是在客户端开辟的一块可存储用户信息的地方:Session是在服务器内存中开辟的一块存储用户信息的地方.JavaScript ...

  7. python lambda ,map详解

    lambda 匿名函数 # 普通定义函数 def func1(x,y): return x+y # 执行函数 print(func(1,2)) # 如果此函数只调用一次,或者功能简单,此方法就显得笨拙 ...

  8. 1、spring与springmvc父子容器

    转载于http://www.tianshouzhi.com/api/tutorials/spring 1.0 spring与springmvc父子容器 1.spring和springmvc父子容器概念 ...

  9. AcWing 893. 集合-Nim游戏

    //只能拿某些特定个数的石子 #include <cstring> #include <iostream> #include <algorithm> #includ ...

  10. 短网址url接口api,url短链接(t.cn、url.cn)生成

    简要说明 短网址api接口有很多格式,不同的接口生成的短网址格式也不同,比如常见的t.cn.url.cn.w.url.cn等格式.总而言之短网址接口就是用来将一个冗长的链接缩短成10个字符以内的短链接 ...