使得程序更加简洁,lambda表达式的类型在C++11中被

作者:澳门娱乐

  lambda表达式源于函数式编程的概念,它可以就地匿名定义目标函数或函数对象,不需要额外写一个命名函数或者函数对象。lambda表达式的类型在C++11中被称为“闭包类型”,也可以理解为是一个仿函数(带operator()类),其语法形式如下:

lambda表达式是C++11引入的新特性,用于声明一个函数,因为不需要对这个函数指定函数名,故lambda表达式声明的是匿名函数。lambda来源于函数式编程的概念,也是现代编程语言的一个特点。

  [capture] (params) opt -> ret {body;};


  capture: 捕获列表;

lambda表达式具有如下优点:

  params: 参数列表;

(1)声明式编程风格:匿名定义函数,不需要额外命名函数,可以更直接地写程序。

  opt: 函数选项;

(2)在需要的时间和地点实现功能闭包,使编写程序更加灵活。因为其不需要额外命名函数,避免了代码膨胀和功能分散,使得程序更加简洁。

  ret: 返回值类型;


  body: 函数体。

lambda表达式的语法如下:

  很多时候,lambda表达式的返回值是非常明显的,C++11中允许省略lambda表达式的返回值定义,即去掉“-> ret”部分,这样编译器就会自动推导出返回值类型。一个简单的lambda表达式如下:  

[caputrue](params)opt -> ret { body; };

#include "stdafx.h"
#include<iostream>// std::cout

int main()
{
    auto f = [](int a, int b) -> int {return (a*b); };
    std::cout << f(3, 4) << std::endl; // output:12

    return 0;
}

(1)caputrue是捕获列表。指明了lambda表达式能访问的外部变量(lambda表达式函数体之外的变量),以及如何访问这些变量。具体情况如下:

  lambda表达式中的捕获字段非常有用,捕获的意思是捕获外部变量在lambda函数体内部使用,有以下几种不同的捕获方式:

[] 不捕获任何外部变量

  []:不捕获外部的任何变量,如果在函数体内使用外部变量就会报错;

[&] 按引用捕获,即捕获外部作用域中所有变量,并作为引用在函数体中使用。

  [&]:以引用的方式捕获外部的所有变量,如果在函数体内改变外部变量值,外部变量值就会随之改变;

[=] 按值捕获,即捕获外部作用域中所有变量,并作为值副本在函数体中使用。

  [=]:以值的方式捕获外部的所有变量,如果在函数体内改变“外部变量值”,外部变量值不会改变;

[=,&a] 按值捕获外部作用域中所有变量,并按引用捕获a变量。

  [=, &foo]:以值得方式捕获外部所有变量,并以引用的方式捕获foo变量;

[b] 按值捕获b变量,同时不捕获其他变量。

  [bar]:以值得方式捕获bar变量,其他外部变量不捕获;

[this] 应用于类中。捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样的访问权限,从而可以在lambda中使用当前类的成员函数和成员变量。如果已经在捕获列表中使用了&或者=,那么就默认添加了该选项。

  [this]:捕获当前类中的this指针,让lambda表达式拥有和当前类成员函数同样的访问权限。如果已经使用了&或者=,则this是默认添加的。

(2)params是参数列表。表示传给lambda表达式的参数序列,选填。

  注意按值捕获和按引用捕获的区别,按值捕获将在lambda表达式中用到的外部变量进行了一份拷贝并且保存到了lambda闭包类型中,如果之后对所用到的外部变量进行修改,lambda表达式中用到的变量是不会改变的,因为该变量只是一份拷贝;按引用捕获则是直接对变量的值进行读取或操作,如代码所示:

(3)opt是函数选项。可以填mutable,exception,attribute(选填一个或者多个)。

#include "stdafx.h"
#include<iostream>// std::cout

int main()
{
    int numA = 0;
    int numB = 0;
    {
        auto f1 = [] {return numA; };// error,没有捕获外部变量
        auto f2 = [&numB] {return (--numB); };
        f2();
        std::cout << numB << std::endl;// -1
    }

    int numC = 100;
    int numD = 100;
    auto f3 = [=]() -> int {return (numC*numD); };
    numD = 99;
    std::cout << f3() << std::endl; // output:10000

    return 0;
}

  有了lambda表达式,我们在使用for循环或者std::for_each的时候,就可以改写成如下形式:

#include "stdafx.h"
#include<iostream>// std::cout
#include<list>
#include <algorithm>
int main()
{
    std::list<int> l = { 1, 3, 5, 87, 64, 33, 0, -1, -100};
    int nCount = 0;
    std::for_each(l.begin(), l.end(), [&nCount](int val) {if (val > 50) nCount++; });
    std::cout << "The number larger than 50 in l is: " << nCount << std::endl;

    return 0;
}

mutable:说明lambda表达式体内的代码可以修改被捕获的变量,如果被捕获的变量是一个对象则可以调用该对象的non-const函数。

澳门娱乐6165,  总结一下,lambda表达式看起来和Java里边的匿名函数比较像,使用lambda表达式后,可以使程序变得非常简洁。但是,如果使用的lambda表达式包含的内容过多,或者lambda表达式的实体是好多地方都会用到的功能性函数,还是单独列出一个函数比较方便。

exception:说明lambda表达式是否抛出异常。

 

attribute:用来声明函数属性。

(4)ret是返回类型,选填。

(5)body是函数体。


下面以在类中声明lambda表达式为例:

class A{

public:

int a = 0;

void fun(int x, int y){

auto a1 = []{ return a; };    //error,没有捕获外部变量

auto a2 = [=] { return a + x + y; };    //ok

auto a3 = [&] { return a + x + y; };    //ok

auto a4 = [this] { return a; };    //ok

auto a5 = [this]{return a + x + y; };  /*error,因为x,y不是类成员变量,而且没有捕获x,y*/

auto a6 = [this, x, y]{ return a + x + y; };    //ok

auto a7 = [this]{ return a ++; };    //ok

}


注意事项:

1、lambda表达式的延迟调用。lambda表达式按值捕获外部变量时,在捕获的瞬间,外部变量的值就被复制了,之后该外部变量值的改变不会对之前捕获到的值有影响。如果希望lambda表达式在调用时即时访问外部变量,应该使用引用方式捕获。

int a = 0;

auto func1 = [=] { return a; };

a ++;

std::cout << func1() << std::endl;    //输出0

int b = 0;

auto func2 = [&b]{ return b; };

b ++;

std::cout << func2() << std::endl;    //输出1

2、按值捕获外部变量时,在lambda表达式中修改它们的副本并不会影响外部的值,但我们仍然无法修改这些副本。如果想修改这些副本,需要显示声明lambda表达式为mutable。lambda表达式定义的是仿函数闭包。lambda表达式捕获到的任何外部变量,最终均会变为闭包类型的成员变量。按照C++11标准,lambda表达式的operator()默认是const的,一个const成员函数是无法修改成员变量的值的。而mutable就取消了operator()的const。

注:被mutable修饰的lambda表达式就算没有参数也要显示写明参数列表。

int a = 0;

auto func1 = [=] { return a++; };    //error

auto func2 = [=] () mutable { return a++; };    //ok

本文由澳门娱乐6165发布,转载请注明来源

关键词: