1 它的结构

一条lambda表达式一般会有以下部分:

1.一个可能为空的捕获列表,指明定义环境中的那些名字能被用在lambda表达式内,以及这些名字的访问形式拷贝还是引用,捕获列表位于 [] 内。

2.一个可选的参数列表,指明lambda表达式所需的参数,参数列表位于 () 内。

3.一个可以选的mutable修饰符,指明该lambda表达式可能会修改它自身的状态(即,改变通过值捕获的变量的副本)

4.一个可选的 -> 形式的返回类型声明

5.一个表达式体,指明要执行的代码,表达式位于 {} 内。

[捕获列表](参数列表) mutable(可选) 异常属性 -> 返回类型 {
// 函数体
}

上面的语法规则除了 [捕获列表] 内的东西外,其他部分都很好理解,只是一般函数的函数名被略去, 返回值使用了一个 -> 的形式进行。

所谓捕获列表,其实可以理解为参数的一种类型,lambda 表达式内部函数体在默认情况下是不能够使用函数体外部的变量的, 这时候捕获列表可以起到传递外部数据的作用。

在lambda中,传参、返回结果以及定义表达式体和普通的函数都是一致的,区别就在于普通函数没有提供局部变量“捕获”功能,而局部捕获的功能,就意味着lambda可以做局部函数使用,而普通函数不能。

展示一个小例子证明lambda表达式的简洁性:

Greater than 是一个函数对象,保存了要比较的值:

struct Greater_than {
  int val;
  Greater_than(lnt v) : val{v} { }  ;
 bool operatorO(const pair& r) { return r.second>val};
};

我们也可以使用 lambda 表达式 :

auto p =find_if(m.beginO, m.endO, 
[](const pair& r) { return r.second>42; }); 

 

每当你定义一个lambda表达式后,编译器会自动生成一个匿名类(这个类当然重载了()运算符),我们称为闭包类型(closure type)。

2 基本的参数分析

C++11中的Lambda表达式捕获外部变量主要有以下形式:

在上面的捕获方式中,注意最好不要使用[=]和[&]默认捕获所有变量。首先说默认引用捕获所有变量,你有很大可能会出现悬挂引用(Dangling references),因为引用捕获不会延长引用的变量的声明周期,例如一个形参传进来我们进行捕获并作为一个返回值执行。因为函数传参进来之后,本函数不会保存该变量,函数执行完就会自动释放,那么这个时候返回值就可能产生一个没有意义的结果。​​​​​​

auto evt_set_status_x = [&](EventType x){  status[x] = true;/*通过引用捕获的变量 我们可以进行修改变量的数据*/};


    [&]是一个捕获列表(  capture l ist ), 它指明所用的局部名字(如 x) 将通过引用访问 。如果我们希望只"捕获 "x ,则可以写成 [&x] ;如果希望给生成的函数对象传递一个  的拷贝, 则写成[ x] 。什么也不捕获是[],捕获所有通过引用访问的局部名字是[&],捕获所有以值访问的局部名字是[=]  。     

并且lambda表达式也可以赋值给相对应的函数指针,这也使得你完全可以把lambda表达式看成对应函数类型的指针。

当我们需要访问它的局部变量的时候,我们需要特别定义捕获列表中的类型

下面是一个没有使用局部变量的lambda表达式,所以它的[]里面为空

​​​​​​​

void part(vector& v){    
  sort(v.begin,v.end);//排列值
   sort(v.begin,v.end,            
    [](int x,int y){return abs(x) < abs(y);});//排列绝对值
}

下面是一个使用局部变量的lambda表达式,所以它的[]里面为空就会出错​​​​​​​

void part(vector& v){    
  bool value = true;
    sort(v.begin,v.end,            [](int x,int y){return  value ? x<y:abs(x) < abs(y);});
}

这时候就错误了,因为我们用到了value这个局部变量,而没有进行捕获列表的设置。

3 捕获使用分析

使用 lambda 虽然简单便捷,但也有可能显得晦涩难懂 。

值捕获

与参数传值类似,值捕获的前提是变量可以拷贝,不同之处则在于,被捕获的变量在 lambda 表达式被创建时拷贝, 而非调用时才拷贝:

​​​​​​​

#include 
void value_capture() {
    int value = 1;
    auto copy_value = [value] {
        return value;
    };
    value = 100;
    auto stored_value = copy_value();
    std::cout << "stored_value = " << stored_value << std::endl;
}
int main(int argc,char ** argv)
{
  value_capture();
}
// 这时, stored_value == 1, 而 value == 100.
// 因为 copy_value 在创建时就保存了一份 value 的拷贝

boolc语言_bookcase_c++bool

记得编译的时候加 -std=c++11

引用捕获

与引用传参类似,引用捕获保存的是引用,值会发生变化:

void reference_capture() {
    int value = 1;
    auto copy_value = [&value] {
        return value;
    };
    value = 100;
    auto stored_value = copy_value();
    std::cout << "stored_value = " << stored_value << std::endl;
    // 这时, stored_value == 100, value == 100.
    // 因为 copy_value 保存的是引用
}

boolc语言_bookcase_c++bool

泛型lambda表达式

从C++14开始,lambda表达式支持泛型:其参数可以使用自动推断类型的功能,而不需要显示地声明具体类型。这就如同函数模板一样,参数要使用类型自动推断功能,只需要将其类型指定为auto,类型推断规则与函数模板一样。就用我最早给出的那个例子好了。

auto evt_set_status_x = [&](EventType x){
  status[x] = true;
};

​​​

这就是我分享的c++中的lambda表达式,以后有机会再往深入去分析一哈,其次如果大家有什么更好的思路,欢迎分享交流哈。

限时特惠:本站每日持续更新海量各大内部网赚创业教程,会员可以下载全站资源点击查看详情
站长微信:11082411

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。