[C++] Lambda表达式

参考自:https://www.cnblogs.com/jimodetiantang/p/9016826.html

1.概述

Lambda是c++11中引入的特性,为创建函数提供一种新的方式,用于定义和创建匿名的函数,以简化编程工作。

关于Lambda需要知道:

  • Lambda 函数可以引用在它之外声明的变量. 这些变量的集合叫做一个闭包. 闭包被定义在 Lambda 表达式声明中的方括号 [] 内。编译器为每个Lambda函数生成唯一闭包。

  • Lambda函数不会降低性能,它的性能和普通的函数一样

2.Lambda语法

Lambda完整语法如下所示:

[ capture ] ( params ) mutable exception attribute -> ret { body }    

[C++] Lambda表达式

 2-1 capture字句

capture字句是在[]内的内容,是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义 Lambda 为止时 Lambda 所在作用范围内可见的局部变量(包括 Lambda 所在类的 this)。有以下形式:

  • 空。没有任何函数对象参数。
  • =。函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是值传递方式(相
    当于编译器自动为我们按值传递了所有局部变量)。
  • &。函数体内可以使用 Lambda 所在范围内所有可见的局部变量(包括 Lambda 所在类的 this),并且是引用传递方式
    (相当于是编译器自动为我们按引用传递了所有局部变量)。
  • this。函数体内可以使用 Lambda 所在类中的成员变量。
  • a。将 a 按值进行传递。按值进行传递时,函数体内不能修改传递进来的 a 的拷贝,因为默认情况下函数是 const 的,要
    修改传递进来的拷贝,可以添加 mutable 修饰符。
  • &a。将 a 按引用进行传递。
  • a,&b。将 a 按值传递,b 按引用进行传递。
  • =,&a,&b。除 a 和 b 按引用进行传递外,其他参数都按值进行传递。
  • &,a,b。除 a 和 b 按值进行传递外,其他参数都按引用进行传递。

定义在闭包中的lambda用[]捕获来自调用它的外部的变量, 例如,如果 lambda 体通过引用访问外部变量 total 并通过值访问外部变量 factor,则以下 capture 子句等效:

[&total, factor]
[factor, &total]
[&, factor]
[factor, &]
[=, &total]
[&total, =]

在 C++14 中,可在 Capture 子句中引入并初始化新的变量,而无需使这些变量存在于 lambda 函数的封闭范围内。 初始化可以任何任意表达式表示;且将从该表达式生成的类型推导新变量的类型。 此功能的一个好处是,在 C++14 中,可从周边范围捕获只移动的变量(例如 std::unique_ptr)并在 lambda 中使用它们。例:

1 pNums = make_unique<vector<int>>(nums);
2 //...
3       auto a = [ptr = move(pNums)]()
4         {
5            // use ptr
6         };

这里注意,当以[=]方式进行捕捉时,传递到Lambda中的值视为常量,只会初始化一次,下例可以演示该情况。

 1 int main()
 2 {
 3     int i = 10;
 4     auto f = [=]() {
 5         std::cout<< i << std::endl;
 6     };
 7     f();
 8     i++;
 9     f();
10 }

即使i在第2次使用时已进行过一次自加,输出仍然为10。

2-2 参数列表

标识重载的 () 操作符的参数,没有参数时,这部分可以省略。参数可以通过按值(如: (a, b))和按引用 (如: (&a, &b)) 两种方式进行传递。
在C++ 14,如果参数类型是泛型,则可以使用 auto 关键字作为类型说明符。 这将告知编译器将函数调用运算符创建为模板。 参数列表中的每个 auto 实例等效于一个不同的类型参数。

2-3 mutable声明

这部分可以省略。

按值传递函数对象参数时,加上 mutable 修饰符后,可以修改传递进来的拷贝(注意是能修改拷贝,而不是值本身)。

2-4 exception声明

这部分可以省略。

exception 声明用于指定函数抛出的异常,如抛出整数类型的异常,可以使用 throw(int)。
可以使用 noexcept 异常规范来指示 lambda 表达式不会引发任何异常。

2-5 返回类型

标识函数返回值的类型,当返回值为 void,或者函数体中只有一处 return 的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。

2-6 函数体

标识函数的实现,这部分不能省略,但函数体可以为空。

普通函数和 lambda 表达式的主体均可访问以下变量类型:

  • 从封闭范围捕获变量,如前所述。

  • 参数

  • 本地声明变量

  • 类数据成员(在类中声明时)并被捕获

  • 具有静态存储持续时间的任何变量(例如,全局变量)

3.Lambda和std::function

可以利用lambda对std::function进行赋值,赋值时编译器会检查两者的参数类型和返回类型,类型不一致时编译器会优先尝试类型的转换,不能转换的情况会编译错误。

示例如下:

 1 #include <iostream>
 2 #include <string>
 3 #include <functional>
 4 using namespace std;
 5 
 6 
 7 double global_f(int n) {
 8     cout << "global_f()" << endl;
 9     return static_cast<double>(n++);
10 }
11 
12 int main() {
13     std::function<double(int)> f;
14     cout << "sizeof(f) == " << sizeof(f) << endl;
15 
16     int n = 10;
17     f = global_f;
18     cout << f(n) << endl;
19 
20     f = [](double n)->double { 
21         cout << "Lambda" << endl; 
22         return static_cast<double>(n++);
23     }; 
24     cout << f(n) << endl;
25 
26 }

 

 

原文链接: https://www.cnblogs.com/Asp1rant/p/13227203.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    [C++] Lambda表达式

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/361380

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 下午1:47
下一篇 2023年3月2日 下午1:48

相关推荐