C++11中的Lambda表达式

本文地址:http://www.cnblogs.com/archimedes/p/c11-lambda.html,转载请注明源地址。

“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。

ISO C++ 11 标准的一大亮点是引入Lambda表达式。基本语法如下:

[capture list] (parameter list) ->return type { function body }

其中除了“[ ]”(其中捕获列表可以为空)和“复合语句”(相当于具名函数定义的函数体),其它都是可选的。它的类型是唯一的具有成员operator()的非联合的类类型,称为闭包类型(closure type)。

C++中,一个lambda表达式表示一个可调用的代码单元。我们可以将其理解为一个未命名的内联函数。

它与普通函数不同的是,lambda必须使用尾置返回来指定返回类型。

例如:调用<algorithm>中的std::sort,ISO C++ 98 的写法是要先写一个compare函数:

bool compare(int &a, int &b)
{
    return a > b;  //降序排序
}

然后,再这样调用:

sort(a, a + n, compare);

然而,用ISO C++ 11 标准新增的Lambda表达式,可以这么写:

sort(a, a + n, [](int a, int b){return a > b;});   //降序排序

这样一来,代码明显简洁多了。

由于Lambda的类型是唯一的,不能通过类型名来显式声明对应的对象,但可以利用auto关键字和类型推导:

auto f = [](int a, int b){return a > b;});

和其它语言的一个较明显的区别是Lambda和C++的类型系统结合使用,如:

autof = [x](int a, int b){return a > x;});//x被捕获复制
int x = 0,y = 1;
auto g = [&](int x){return ++y;});//y被捕获引用,调用g后会修改y,需要注意y的生存期
bool(*fp)(int, int) = [](int a, int b){return a > b;});//不捕获时才可转换为函数指针

Lambda表达式可以嵌套使用。

即将出版的ISO C++14支持基于类型推断的泛型lambda表达式。上面的排序代码可以这样写:

sort(a, a + n, [](const auto &a, const auto &b){return a > b;});//降序排序:不依赖a和b的具体类型

因为参数类型和函数模板参数一样可以被推导而无需和具体参数类型耦合,有利于重构代码;和使用auto声明变量的作用类似,它也允许避免书写过于复杂的参数类型。特别地,不需要显式指出参数类型使使用高阶函数变得更加容易。

下面举一个简单使用Lambda表达式的例子:

#include<iostream>
#include<algorithm>
#include<vector>
#include<ostream>
using namespace std;
int main()
{
    vector<int> v;
    for (int i = 0; i < 10; i++){
        v.push_back(i);
    }
    for_each(v.begin(), v.end(), [](int n){cout << n << " "; });
    cout << endl;
    return 0;
}

Lambda表达式默认的返回类型为void

为了对比,下面使用函数对象实现相同功能的代码:

#include<iostream>
#include<algorithm>
#include<vector>
#include<ostream>
#include<cassert>
using namespace std;

class LambdaFunctor{
public:
    void operator()(int n) const{
        cout << n << " ";
    }
};

int main()
{
    vector<int> v;
    for (int i = 0; i < 10; i++){
        v.push_back(i);
    }
    for_each(v.begin(), v.end(), LambdaFunctor());
    cout << endl;
    return 0;
}

对比一下,就会发现使用Lambda表达式要简洁得多

上面提到的Lambda表达式可以操作所在作用域的变量,这需要通过被称为“捕获”的特殊语法来实现,就是通过在[]内列出将要捕获的“外部”变量列表,这样在函数体内就可以访问并操作这些变量。参考下面的代码:

#include<iostream>
#include<algorithm>
#include<vector>
#include<ostream>
#include<cassert>
using namespace std;

int main()
{
    vector<int> v;
    for (int i = 0; i < 10; i++){
        v.push_back(i);
    }
    //使用for_each语句和Lambda表达式来实现对偶元素的计数

    int evenCount = 0;
    for_each(v.begin(), v.end(), [&evenCount](int n){
        cout << n;
        if (n % 2 == 0) {
            cout << " is even" << endl;
            evenCount++;
        }
        else {
            cout << " is odd" << endl;
        }
    });
    cout << "There are " << evenCount << " even numbers in the vector." << endl;
    getchar();
    return 0;
}

参考资料

百度百科

《Visual C++2010权威开发指南》

时间: 2024-10-18 23:54:21

C++11中的Lambda表达式的相关文章

C++11新特性——lambda表达式

C++11的一大亮点就是引入了Lambda表达式.利用Lambda表达式,可以方便的定义和创建匿名函数.对于C++这门语言来说来说,"Lambda表达式"或"匿名函数"这些概念听起来好像很深奥,但很多高级语言在很早以前就已经提供了Lambda表达式的功能,如C#,Python等.今天,我们就来简单介绍一下C++中Lambda表达式的简单使用. 声明Lambda表达式 Lambda表达式完整的声明格式如下: [capture list] (params list) m

C#中的Lambda表达式和表达式树

在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化.但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响.C# 3.0中出现的Lambda表达式在不牺牲可读性的前提下,进一步简化了委托. LINQ的基本功能就是创建操作管道,以及这些操作需要的任何状态.这些操作表示了各种关于数据的逻辑,例如数据筛选,数据排序等等.通常这些操作都是用委托来表示.Lambda表达式是对LINQ数据操作的一种符合语言习惯的表示方式. Lambda表达式不仅可以用来创

c++ 11学习笔记--Lambda 表达式(对比测试Lambda ,bind,Function Object)

所有c++ coder都应该为这个语法感到高兴,说的直白一点,Lambda 表达式就是函数对象的语法糖. 还是直接看对比栗子吧,抄袭的是msdn的官网 该示例使用 for_each 函数调用中嵌入的 lambda 向控制台打印 vector 对象中的每个元素是偶数还是奇数. 使用lambda #include <algorithm> #include <iostream> #include <vector> using namespace std; int main()

[转]C++中的Lambda表达式

原文地址:C++中的Lambda表达式 作者:果冻想 一直都在提醒自己,我是搞C++的:但是当C++11出来这么长时间了,我却没有跟着队伍走,发现很对不起自己的身份,也还好,发现自己也有段时间没有写C++代码了.今天看到了C++中的Lambda表达式,虽然用过C#的,但是C++的,一直没有用,也不知道怎么用,就可怜的连Lambda语法都看不懂.好了,这里就对C++中的Lambda进行一个简单的总结,就算是对自己的一个交代,我是搞C++的,我是一个C++ programmer. 一段简单的Code

Java语言与JVM中的Lambda表达式

Lambda表达式是自Java SE 5引入泛型以来最重大的Java语言新特性,本文是2012年度最后一期Java Magazine中的一篇文章,它介绍了Lamdba的设计初衷,应用场景与基本语法. Lambda表达式,这个名字由该项目的专家组选定,描述了一种新的函数式编程结构,这个即将出现在Java SE 8中的新特性正被大家急切地等待着.有时你也会听到人们使用诸如闭包,函数直接量,匿名函数,及SAM(Single Abstract Method)这样的术语.其中一些术语彼此之间会有一些细微的

Qt5中的lambda表达式和使用lambda来写connect

c11新特性中加入了lambda表达式,所以Qt 也支持 需在.pro文件中加入 CONFIG += c++11 例子: QString program = "C:/Windows/System32/cmd.exe"; QStringList arguments; arguments << "/c" << "dir" << "C:\\"; QProcess* cmdProcess = new

编写高质量代码改善C#程序的157个建议——建议27:在查询中使用Lambda表达式

建议27:在查询中使用Lambda表达式 LINQ实际上是基于扩展方法和Lambda表达式的.任何LINQ查询都能通过扩展方法的方式来代替. var personWithCompanyList = from person in personList select new { PersonName = person.Name, CompanyName = person.CompanyID==0?"Micro":"Sun" }; foreach (var item in

Android第4坑:Android项目中使用lambda表达式

Android项目中使用lambda表达式或Java8新特性,需要在app/build.gradle中添加如下配置 android { ... defaultConfig { ... jackOptions.enabled = true } compileOptions{ sourceCompatibility org.gradle.api.JavaVersion.VERSION_1_8 targetCompatibility org.gradle.api.JavaVersion.VERSION

Android 中使用Lambda表达式

Android Studio默认使用Lambda表达式是会报错的,即使你使用的是java 8,为了在android studio中使用lambda表达式,我们必须借助一个插件retrolambda ,该插件将java 8中的lambda表达式特性兼容到java 5.使用它也很简单. 首先先项目根目录下的build.gradle中加入 classpath 'me.tatarka:gradle-retrolambda:3.2.0' 最终整个文件会像这样子 buildscript { reposito