C++11之Lambda表达式

导读:本篇文章讲解 C++11之Lambda表达式,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

目录

1.概念和基本用法

 1.1. 基本语法

1.2. 捕获列表释义

1.3. lambda表达式的类型

2.使用


1.概念和基本用法

 1.1. 基本语法

Lambda表达式定义一个匿名函数,并可以捕获一定范围内的变量。
    语法形式如下:

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

            //@ capture–捕获列表
            //@  params–参数列表
            //@  opt–函数选项
            //@  ret–返回值类型
            //@  body–函数体

示例:

auto f = [] (int a) -> int { return a+1;}
std::cout << f(1) << std::endl;//输出2
auto f1 = [] {return 1;}

Lambda表达式是通过返回值后置语法]定义的。
Lambda表达式没有参数列表时,参数列表是可以省略的,如上第三行写法是正确的。

1.2. 捕获列表释义

捕获列表捕获一定范围内的变量:

  •  [] 不捕获任何变量;
  •  [&] 捕获外部作用域中所有变量,并作为引用在函数体中使用–按引用捕获;
  •  [=] 捕获外部作用域中所有变量,并作为副本在函数体中使用–按值捕获;
  •  [=,&foo] 按值捕获外部作用域所有变量,并按引用捕获foo变量;
  •  [bar] 按值捕获bar变量,不捕获其它变量;
  •  [this] 捕获当前类中的this指针,让Lambda表达式拥有和当前类成员函数同样的访问权限。捕获this的目的是可以在Lambda中使用当前类的成员函数和成员变量。

如下代码便于更好理解。
例一:

 

class A
{
public:
    int i=0;
    void FuncTest(int x,int y)
    {
        auto x1 = [] { return i; };//error,没有捕获到外部变量i,会提示"i 未声明的标识符"
        auto x2 = [=] { return (i+x+y); };//OK,捕获所有变量
        auto x3 = [&] {return (i+x+y);};//OK,捕获所有变量
        auto x4 = [this] {return i;};//OK,捕获类A的this指针
        auto x5 = [this] {return (i+x+y);};//error,捕获this指针是为了使用当前类的成员函数和成员变量,会提示错误,无法捕获x,y
        auto x6 = [this,x,y] {return i+x+y;};//OK,捕获类A的this指针和x,y
        auto x7 = [this] {return i++;};//OK,捕获this指针,并修改成员变量
    }
};

例二:

    int m = 0,n = 1;
    auto f1 = [] {return m;};    //error,没有捕获外部变量,会提示错误:无法隐式捕获m,因为未指定默认捕获模式
    auto f2 = [&] {return m++;};    //OK,捕获外部所有变量,并对m进行自加运算
    auto f3 = [=] {return m;};    //OK,捕获外部变量,并返回m
    auto f4 = [=] {return m++;};    //error,m是以按值的方式捕获的,没有办法修改,会提示错误:m 无法在非可变lambda中修改通过复制捕获
    auto f5 = [m] {return m+n;};    //error,并没有捕获n,会提示错误:无法隐式捕获n
    auto f6 = [m,&n] {return m+(n++);};    //OK,m按值方式捕获,n按引用捕获,可以自加
    auto f7 = [=,&n] {return m+(n++);};    //OK,捕获外部所有变量和n的引用,对n做自加运算

以上可以看出来lambda表达式的捕获列表控制lambda表达式能够访问的外部变量,以及如何访问这些变量。

默认状态下lambda表达式无法修改通过复制方式捕获的外部变量,如果要修改这些变量的话,需要使用引用方式进行捕获。

如果希望修改按值捕获的外部变量,需要显示指明lambda表达式为mutable,即:

int a=0;
auto f1 = [=] {return a++;};    //error
auto f2 = [=] () mutable {return a++;};    //ok,mutable修饰的lambda表达式就算没有参数也要写明参数列表.

1.3. lambda表达式的类型

lambda表达式的类型在C++11中被称为”闭包类型”,是一个特殊的,匿名的非nunion的类类型。
可以使用*std::function*和*std::bind*来存储和操作lambda表达式。

std::function<int(int)> f1 = [](int a) { return a;};
std::function<int(void)> f2 = std::bind( [] (int a) {return a;},123};

另外,对于**没有捕获任何变量**的lambda表达式,还可以被转换成一个普通的函数指针:

using func_t = int(*) (int);
func_t f = [] (int a) { return a;};
f(123);

按照C++标准,lambda表达式的operator()默认是const的,mutable作用就是取消operator()的const。

2.使用

示例一:调用for_each函数将vector中的偶数打印出来
使用lambda表达式之前:

class CountEvent
{
    int& m_cout;
public:
    CountEvent(int& count)
        :m_cout(count)
    {

    }
    void operator() (int val)
    {
        if(!(val & 1))
        {
            ++m_cout;
        }
    }
};
    vector<int> v = {1,2,3,4,5,6};
    int event_count = 0;
    for_each(v.begin(),v.end(),CountEvent(event_count));
    cout << "the numbers of even is " << event_count << endl;

使用lambda表达式,用闭包概念替换到仿函数operator(),如下:

vector<int> v = {1,2,3,4,5,6};
int event_count = 0;
for_each(v.begin(),v.end(),[&event_count] (int val)
{
    if(!(val&1))
            ++event_count;
});
cout << "the numbers of even is " << event_count << endl;

这两种写法效果是一样的,都可以求出最终的结果,可以看出使用lambda表达式之后代码很简洁清晰。
lambda表达式的价值在于,就地封装短小的功能闭包,可以极其方便的表达出我们希望执行的操作。

参考书籍:《深入应用C++11 代码优化与工程级应用》–祁宇

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/46140.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!