C++11 lambda表达式

原文出处:https://blog.csdn.net/liukang325/article/details/53610869

如下图,lambda表达式由下面几个部分构成:
这里写图片描述

C++11 的 lambda 表达式规范如下:

  • [ capture ] ( params ) mutable exception attribute -> ret { body }
    是完整的 lambda 表达式形式
  • [ capture ] ( params ) -> ret { body }
    const 类型的 lambda 表达式,该类型的表达式不能改捕获(“capture”)列表中的值
  • [ capture ] ( params ) { body }
    省略了返回值类型的 lambda 表达式,返回类型由 return 语句的返回类型确定;若无return语句,则类似void
  • [ capture ] { body }
    省略了参数列表,类似于无参函数 f()

mutable 修饰符说明 lambda 表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获对象的 non-const 方法。

exception 说明 lambda 表达式是否抛出异常(noexcept),以及抛出何种异常,类似于void f() throw(X, Y)。

attribute 用来声明属性。


另外,capture 指定了在可见域范围内 lambda 表达式的代码内可见得外部变量的列表,具体解释如下:

  • [a,&b] a变量以值的方式呗捕获,b以引用的方式被捕获。
  • [this] 以值的方式捕获 this 指针。
  • [&] 以引用的方式捕获所有的外部自动变量(包括this)。
  • [=] 以值的方式捕获所有的外部自动变量(包括this)。
  • [] 不捕获外部的任何变量。

    下面放些例子,更好的理解lambda表达式

int a = 1;
int b = 2;

auto func = [=, &b](int c)->int {return b += a + c;};
    
    
  • 1
  • 2
  • 3
  • 4

关于capture 中值[=]和引用[&]的区别

下面是其它人博客中看到一些容易出错的lambda的用法:

#include<iostream>         
using namespace std;       

int main()                 
{                          
    int j = 10;            
    auto by_val_lambda = [=]{ return j + 1; };
    auto by_ref_lambda = [&]{ return j + 1; };
    cout<<"by_val_lambda: "<<by_val_lambda()<<endl; // 11
    cout<<"by_ref_lambda: "<<by_ref_lambda()<<endl; // 11

    ++j;                   
    cout<<"by_val_lambda: "<<by_val_lambda()<<endl; // 11
    cout<<"by_ref_lambda: "<<by_ref_lambda()<<endl; // 12

    return 0;              
}
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

第三个输出为什么不是12呢?
在by_val_lambda中,j被视为一个常量,一旦初始化后不会再改变(可以认为之后只是一个跟父作用域中j同名的常量),
而在by_ref_lambda中,j仍然在使用父作用域中的值。
所以,在使用Lambda函数的时候,如果需要捕捉的值成为Lambda函数的常量,我们通常会使用按值传递的方式捕捉;
相反的,如果需要捕捉的值成成为Lambda函数运行时的变量,则应该采用按引用方式进行捕捉。


关于 mutable 的深度理解
默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。按照规定,一个const的成员函数是不能在函数体内修改非静态成员变量的值

#include<iostream>                  
using namespace std;                

int main()                          
{                                   
    int val = 0;  
    // 对于const的成员函数,修改非静态的成员变量,所以就出错了                                  
    // auto const_val_lambda = [=](){ val = 3; }; wrong!!!

    auto mutable_val_lambda = [=]() mutable{ val = 3; };
    mutable_val_lambda();           
    cout<<val<<endl; // 0

    // 而对于引用的传递方式,并不会改变引用本身,而只会改变引用的值,因此就不会报错了                 
    auto const_ref_lambda = [&]() { val = 4; };
    const_ref_lambda();             
    cout<<val<<endl; // 4

    auto mutable_ref_lambda = [&]() mutable{ val = 5; };
    mutable_ref_lambda();           
    cout<<val<<endl; // 5

    return 0;      
}
    
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
原文出处:https://blog.csdn.net/liukang325/article/details/53610869

如下图,lambda表达式由下面几个部分构成:
这里写图片描述

C++11 的 lambda 表达式规范如下:

  • [ capture ] ( params ) mutable exception attribute -> ret { body }
    是完整的 lambda 表达式形式
  • [ capture ] ( params ) -> ret { body }
    const 类型的 lambda 表达式,该类型的表达式不能改捕获(“capture”)列表中的值
  • [ capture ] ( params ) { body }
    省略了返回值类型的 lambda 表达式,返回类型由 return 语句的返回类型确定;若无return语句,则类似void
  • [ capture ] { body }
    省略了参数列表,类似于无参函数 f()

mutable 修饰符说明 lambda 表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获对象的 non-const 方法。

exception 说明 lambda 表达式是否抛出异常(noexcept),以及抛出何种异常,类似于void f() throw(X, Y)。

attribute 用来声明属性。


另外,capture 指定了在可见域范围内 lambda 表达式的代码内可见得外部变量的列表,具体解释如下:

  • [a,&b] a变量以值的方式呗捕获,b以引用的方式被捕获。
  • [this] 以值的方式捕获 this 指针。
  • [&] 以引用的方式捕获所有的外部自动变量(包括this)。
  • [=] 以值的方式捕获所有的外部自动变量(包括this)。
  • [] 不捕获外部的任何变量。

    下面放些例子,更好的理解lambda表达式

int a = 1;
int b = 2;

auto func = [=, &b](int c)->int {return b += a + c;};
  
  
  • 1
  • 2
  • 3
  • 4

关于capture 中值[=]和引用[&]的区别

下面是其它人博客中看到一些容易出错的lambda的用法:

#include<iostream>         
using namespace std;       

int main()                 
{                          
    int j = 10;            
    auto by_val_lambda = [=]{ return j + 1; };
    auto by_ref_lambda = [&]{ return j + 1; };
    cout<<"by_val_lambda: "<<by_val_lambda()<<endl; // 11
    cout<<"by_ref_lambda: "<<by_ref_lambda()<<endl; // 11

    ++j;                   
    cout<<"by_val_lambda: "<<by_val_lambda()<<endl; // 11
    cout<<"by_ref_lambda: "<<by_ref_lambda()<<endl; // 12

    return 0;              
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

第三个输出为什么不是12呢?
在by_val_lambda中,j被视为一个常量,一旦初始化后不会再改变(可以认为之后只是一个跟父作用域中j同名的常量),
而在by_ref_lambda中,j仍然在使用父作用域中的值。
所以,在使用Lambda函数的时候,如果需要捕捉的值成为Lambda函数的常量,我们通常会使用按值传递的方式捕捉;
相反的,如果需要捕捉的值成成为Lambda函数运行时的变量,则应该采用按引用方式进行捕捉。


关于 mutable 的深度理解
默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。按照规定,一个const的成员函数是不能在函数体内修改非静态成员变量的值

#include<iostream>                  
using namespace std;                

int main()                          
{                                   
    int val = 0;  
    // 对于const的成员函数,修改非静态的成员变量,所以就出错了                                  
    // auto const_val_lambda = [=](){ val = 3; }; wrong!!!

    auto mutable_val_lambda = [=]() mutable{ val = 3; };
    mutable_val_lambda();           
    cout<<val<<endl; // 0

    // 而对于引用的传递方式,并不会改变引用本身,而只会改变引用的值,因此就不会报错了                 
    auto const_ref_lambda = [&]() { val = 4; };
    const_ref_lambda();             
    cout<<val<<endl; // 4

    auto mutable_ref_lambda = [&]() mutable{ val = 5; };
    mutable_ref_lambda();           
    cout<<val<<endl; // 5

    return 0;      
}
  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

猜你喜欢

转载自blog.csdn.net/missxy_/article/details/80516288