【C++如此简单】 Lambda表达式

【C++如此简单】 Lambda表达式,第1张

Lambda表达式 lambda 表达式的概念和基本用法
  • C++11特性之一

lambda表达式有如下优点:

  • 声明式编程风格:就地匿名定义目标函数或函数对象,不需要额外写一个命名函数或者函数对象。以更直接的方式去写程序,好的可读性和可维护性。
  • 简洁:不需要额外再写一个函数或者函数对象,避免了代码膨胀和功能分散,让开发者更加集中精力在手边的问题,同时也获取了更高的生产率。
  • 在需要的时间和地点实现功能闭包,使程序更灵活。

lambda表达式用法:

// lambda 表达式定义了一个匿名函数,并且可以捕获一定范围内的变量。
[ capture ] ( params ) opt -> ret { body; };
//  capture 是捕获列表,params 是参数表,opt 是函数选项,ret 是返回值类型,body是函数体。

lambda表达式示例:

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

C++11 中允许省略 lambda 表达式的返回值定义。

auto f = [](int *a*) { return *a* + 1; };  // 编译器就会根据 return 语句自动推导出返回值类型
cout << f(1) << endl;
// 输出2
  • 初始化列表不能用于返回值的自动推导,需要显式给出具体的返回值类型。
  • lambda 表达式在没有参数列表时,参数列表是可以省略的。
使用 lambda 表达式捕获列表

lambda 表达式还可以通过捕获列表捕获一定范围内的变量:

  • [] 不捕获任何变量。
  • [&] 捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。
  • [=] 捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。
  • [=,&foo] 按值捕获外部作用域中所有变量,并按引用捕获 foo 变量。
  • [bar] 按值捕获 bar 变量,同时不捕获其他变量。
  • [this] 捕获当前类中的 this 指针,让 lambda 表达式拥有和当前类成员函数同样的访问权限。如果已经使用了 & 或者 =,就默认添加此选项。捕获 this 的目的是可以在 lamda 中使用当前类的成员函数和成员变量。

lambda表达式易错点:

int a = 0;
auto f = [=](){return a;};
a += 1;
cout << f() << endl;
// 输出0
// lambda 表达式按值捕获了所有外部变量。在捕获的一瞬间,a 的值就已经被复制到f中了。
// 之后 a 被修改,但此时 f 中存储的 a 仍然还是捕获时的值,因此,最终输出结果是 0。
// 如果希望 lambda 表达式在调用时能够即时访问外部变量,我们应当使用引用方式捕获。

如果希望去修改按值捕获的外部变量应当怎么办呢?这时,需要显式指明 lambda 表达式为 mutable:

int a = 0;
auto f1 = [=]{ return a++; };             // error,修改按值捕获的外部变量
auto f2 = [=]() mutable { return a++; };  // OK,mutable
// 被 mutable 修饰的 lambda 表达式就算没有参数也要写明参数列表
lambda 表达式的类型

“闭包类型(Closure Type)”。它是一个特殊的,匿名的非 nunion 的类类型。

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

lambda 表达式可以说是就地定义仿函数闭包的“语法糖”。它的捕获列表捕获住的任何外部变量,最终均会变为闭包类型的成员变量。而一个使用了成员变量的类的 operator(),如果能直接被转换为普通的函数指针,那么 lambda 表达式本身的 this 指针就丢失掉了。而没有捕获任何外部变量的 lambda 表达式则不存在这个问题。

这里也可以很自然地解释为何按值捕获无法修改捕获的外部变量。因为按照 C++ 标准,lambda 表达式的 operator() 默认是 const 的。一个 const 成员函数是无法修改成员变量的值的。而 mutable 的作用,就在于取消 operator() 的 const。

需要注意的是,没有捕获变量的 lambda 表达式可以直接转换为函数指针,而捕获变量的 lambda 表达式则不能转换为函数指针。

声明式的编程风格,简洁的代码

lambda 表达式的价值在于,就地封装短小的功能闭包,可以极其方便地表达出我们希望执行的具体 *** 作,并让上下文结合得更加紧密。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/867572.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-12
下一篇 2022-05-12

发表评论

登录后才能评论

评论列表(0条)

保存