Skip to main content
 首页 » 编程设计

C++匿名函数-Lambda表达式

2022年07月19日29dudu

一、匿名函数简介

1. 为什么存在匿名函数

使用 STL 时,往往会大量用到函数对象,为此要编写很多函数对象类。有的函数对象类只用来定义了一个对象,而且这个对象也只使用了一次,
编写这样的函数对象类就有点浪费。

而且,定义函数对象类的地方和使用函数对象的地方可能相隔较远,看到函数对象,想要查看其 operator() 成员函数到底是做什么的也会比较麻烦。

对于只使用一次的函数对象类,能否直接在使用它的地方定义呢?Lambda 表达式能够解决这个问题。使用 Lambda 表达式可以减少程序中函数对象类的数量,使得程序更加优雅。


2. Lambda匿名表达式的定义形式如下

[外部变量访问方式说明符] (参数表) -> 返回值类型 
{ 
   语句块 
}

其中,"外部变量访问方式说明符" 可以是 '=' 或 '&',表示 "{语句块}" 中用到的、定义在 "{语句块}" 外面的变量在 "{语句块}" 中是否允许被改变。
'=' 表示不允许,'&' 表示允许。当然,在 "{语句块}" 中也可以不使用定义在外面的变量。"-> 返回值类型" 可以省略。

下面是一个合法的Lambda表达式:

[=] (int x, int y) -> bool {return x%10 < y%10; }

Lambda 表达式实际上是一个函数,只是它没有名字。

二、Demo举例

1. 使用Lambda函数按个位排序

#include <iostream> 
#include <algorithm> 
 
using namespace std; 
 
void lambda_test(void) 
{ 
    int a[4] = {11, 2, 33, 4}; 
    sort(a, a+4, [=](int x, int y) -> bool { return x%10 < y%10; } ); 
    for_each(a, a+4, [=](int x) { cout << x << " ";} ); 
} 
 
int main() 
{ 
    lambda_test(); 
     
    return 0; 
} 
 
/* 
$ g++ -std=c++11 function_no_name.cpp -o pp 
$ ./pp 
11 2 33 4 
*/

程序sort使得数组 a 按个位数从小到大排序。具体的原理是:sort 在执行过程中,需要判断两个元素 x、y 的大小时,会以 x、y 作为参数,
调用 Lambda 表达式所代表的函数,并根据返回值来判断 x、y 的大小。这样,就不用专门编写一个函数对象类了。

for_each 的第 3 个参数是一个 Lambda 表达式。for_each 执行过程中会依次以每个元素作为参数调用它,因此每个元素都被输出。

2. Lambda函数内修改外部变量

#include <iostream> 
#include <algorithm> 
 
using namespace std; 
 
int main() 
{ 
    int a[4] = {1, 2, 3, 4}; 
    int total = 0; 
    for_each(a, a + 4, [&](int & x){total += x; x *= 2;}); 
    cout << total << endl;  //输出 10 
    for_each(a, a + 4, [=](int x){cout << x << " ";}); 
 
    return 0; 
} 
 
/* 
$ g++ -std=c++11 lambda_test.cpp -o pp 
$ ./pp 
10 
2 4 6 8 
*/

'[&]'表示该Lambda表达式中用到的外部变量 total 是传引用的,其值可以在表达式执行过程中被改变(如果使用'[=]',编译无法通过)。
该Lambda表达式每次被 for_each 执行时,都将 a 中的一个元素累加到 total 上,然后将该元素加倍。

实际上,"外部变量访问方式说明符" 还可以有更加复杂和灵活的用法。例如:

(1) [=, &x, &y] 表示外部变量 x、y 的值可以被修改,其余外部变量不能被修改.
(2) [&, x, y] 表示除 x、y 以外的外部变量,值都可以被修改。

3. 参数有些可修改有些不可修改

#include <iostream> 
 
using namespace std; 
 
int main() 
{    
    int x = 100, y = 200, z = 300; 
    auto ff = [=, &y, &z](int n) { 
        cout << x << endl; 
        y++; 
        z++; 
        return n*n; 
    }; 
    cout << ff(15) << endl; 
    cout << y << "," << z << endl; 
} 
 
/* 
$ g++ -std=c++11 lambda_test.cpp -o pp 
$ ./pp 
100 
225 
201,301 
*/

定义了一个 auto 类型的变量 ff,auto 表示由编译器自动判断其类型(这也是 C++11 的新特性)。本行将一个Lambda表达式赋值给 ff,
以后就可以通过 ff 来调用该 Lambda 表达式了。

ff(15) 以15作为参数 n 调用上面的Lambda表达式。该Lambda表达式指明,对于外部变量 y z 可以修改其值,对于其他外部变量,例如 x,
不能修改其值。因此在该表达式执行时,可以修改外部变量 y、z 的值,但如果出现试图修改 x 值的语句,就会编译出错。

4. std::thread 构造函数传参也可以传Lambda表达式

#include <iostream> 
#include <thread> 
 
using namespace std; 
 
int main()  
{ 
    char name[32]; 
 
    std::thread ([name](){ 
        pthread_getname_np(pthread_self(), (char*)name, 32); 
        cout << name << endl; 
    }).join(); 
 
    return 0; 
} 
 
/* 
$ g++ -std=c++11 lambda_test.cpp -pthread -o pp 
$ ./pp 
pp 
*/

本文参考链接:https://www.cnblogs.com/hellokitty2/p/16444848.html