C++中有 五种可调用对象:
1. 函数
2. 函数指针
3. lambda表达式
4. 重载了函数调用运算符的类
5. bind创建的对象
函数不能定义在另一个函数内, 但是 lambda表达式可以定义在函数内。
一.什么是 lambda表达式
一个lambda表达式 表示一个可调用的代码单元,可理解为 一个未命名的内联函数。一个lambda表达式具有一个返回类型、一个参数列表 和 一个函数体。表达式形式如下:
[capture list ] ( parameter list) -> return type { function body }
capture list : 捕获列表
return type : 返回类型
parameter list:参数列表
function body: 函数体
捕获规则:
捕获规则是指Lambda表达式捕获外部变量的方式。C++11标准规定了三种捕获方式:
- 值捕获(Capture by value):使用
[=]表示 以值方式 捕获所有的外部变量,Lambda表达式中的外部变量会被复制一份,修改Lambda表达式中的变量不会影响外部变量。- 引用捕获(Capture by reference):使用
[&]表示 以引用方式 捕获所有的外部变量,Lambda表达式中的外部变量是外部变量的引用,修改Lambda表达式中的变量会影响外部变量。[this]表示 以引用方式 捕获当前对象的指针,可以在Lambda表达式中访问当前对象的成员变量和成员函数。- 显式捕获(Explicit capture):使用
[var]表示捕获外部变量var,使用[&var]表示捕获外部变量var的引用,使用[=var]表示捕获外部变量var的副本,使用[&, var]表示以引用方式捕获所有的外部变量并捕获外部变量var的副本,使用[=, &var]表示以值方式捕获所有的外部变量并捕获外部变量var的引用。
Lambda表达式可以使用任意的组合方式,例如[this, a, b](int c){}表示以引用方式捕获当前对象的指针,并以值方式捕获变量a和b,同时接受一个整型参数c。
捕获的时候,这个外部变量,外部的范围是哪些范围?
在Lambda表达式中捕获的外部变量,指的是 Lambda表达式定义的位置所在 的 外部作用域中 的变量。具体来说,Lambda表达式可以捕获以下外部变量:
- 局部变量:Lambda表达式可以捕获定义在Lambda表达式外部作用域中的局部变量,包括函数中的局部变量和全局变量。捕获局部变量的方式和捕获全局变量的方式相同,可以使用值捕获、引用捕获和显式捕获。
- 成员变量:如果Lambda表达式定义在类中,并且使用了
this捕获了当前对象的指针,则Lambda表达式可以访问当前对象的所有成员变量。 - 静态变量:Lambda表达式可以捕获定义在外部作用域中的静态变量,可以使用值捕获、引用捕获和显式捕获。
需要注意的是,Lambda表达式只能捕获定义在Lambda表达式所在的外部作用域中的变量,不能捕获在Lambda表达式内部或者其他作用域中定义的变量。
如果需要在Lambda表达式中使用其他作用域中的变量,可以通过函数参数的方式传递进来。
lambda 必须使用 尾置返回 (比如 [ ](int a)-> int { ...... })来指定返回类型。 如果 忽略返回类型,lambda根据函数体中的代码推断出返回类型。
例如:
auto compare = [](const int a, const int b){ return a > b;}
在Lambda表达式的参数列表中,可以指定函数的参数,也可以使用默认参数,例如([](){})表示一个不带参数的Lambda表达式,([](int a){})表示一个带有一个整型参数的Lambda表达式。
在Lambda表达式的函数体中,可以编写任意有效的C++代码,包括语句、表达式、控制结构等。Lambda表达式可以返回一个值,也可以不返回任何值。
二、lambda的调用
调用方式与普通函数的调用方式相同,都是使用调用运算符() :
1.不使用捕获列表
示例1:
#include <iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
int main()
{
auto compare = [](const int a, const int b) {return a > b; };
cout << "3 与 7的对比结果:"<<compare(3, 7) << endl;
return 0;
}
运行结果是:

示例2:
sort函数,默认是从小到大排序,自定义按照string的大小进行排序
#include <iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
int main()
{
vector<string> mystring = {"a","egg","elephant","piggy","monkey","yellow","ahelkh","walawalawala"};
sort(mystring.begin(), mystring.end(), [](const string a, const string b) {return a.size() > b.size(); });
cout << "sort排序后的结果是:";
for (auto mem:mystring)
{
cout << " " << mem;
}
cout << endl;
system("pause");
return 0;
}
运行结果:

2.使用捕获列表
lambda以一对 [ ] 开始,可以在其中提供一个以逗号分隔的名字列表 , 这些名字都是 它所在函数中定义的。
示例1:
#include <iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
int main()
{
//使用捕获列表
//
string a = "hlloy high";
string b = "what?";
auto compare= [a,b](const string c)
{
return c.size() > a.size() && c.size() >b.size();
};
cout << compare("WoWwwww you get one goald") << endl;
system("pause");
return 0;
}
运行结果是:

示例2:
#include <iostream>
#include<vector>
#include<string>
#include<algorithm>
using namespace std;
int main()
{
vector<string> mystring = {"a","egg","elephant","piggy","monkey","yellow","ahelkh","walawalawala"};
//找到第一个大于6的字符串
int sz = 6;
auto wx = find_if(mystring.begin(), mystring.end(), [sz](const string a) {return a.size() > sz; });
cout <<"第一个大于 sz 大小的字符串是:"<< *wx << endl;
system("pause");
return 0;
}
执行结果是:

三. 关于捕获是在什么时候捕获的
-
按值捕获:在 lambda 定义时 复制变量的当前值,后续对原变量的修改不会影响已捕获的值
-
按引用捕获:捕获变量的引用,后续对原变量的修改会反映在 lambda 中
-
默认捕获:
-
[=]默认按值捕获所有外部变量 -
[&]默认按引用捕获所有外部变量
-
详细说明:
-
按值捕获:它直接捕获的是在 lambda 表达式定义那一刻,外部变量的当前值的一个副本。你可以把它想象成在 lambda 内部创建了一个新的、同名的常量(默认情况下)变量,并用外部变量的值初始化了它。
int x = 10; // 这里,lambda 内部的 'x' 被创建并初始化为 10 auto lambda = [x]() { return x + 1; }; -
按引用捕获:它不是捕获数值,而是捕获了外部变量的引用(别名)。它把外部变量的“门牌号”交给了 lambda。lambda 内部对这个名字的所有操作,都会直接作用到原来的那个变量上。
int x = 10; // 这里,lambda 内部的 ‘x’ 是外部 ‘x’ 的一个别名(引用) auto lambda = [&x]() { x = 20; }; // 这会修改外部的 x
更形象的比喻
让我们用一个比喻来加深理解:
假设外部变量 a 是一个装着水的杯子,里面的水是它的值。
-
按值捕获
[a]:-
行为:在 lambda 定义的那一刻,重新拿一个空杯子,从
a杯子里倒同样多的水到这个新杯子里。 -
结果:lambda 拥有的是一杯独立的水。之后无论你是喝掉原来杯子
a里的水(修改原变量),还是往新杯子里加水,两者都互不影响。
-
-
按引用捕获
[&a]:-
行为:没有新杯子。lambda 只是知道了原来那个杯子
a放在哪里(拿到了它的地址)。 -
结果:lambda 内部对
a的任何操作,比如喝水、倒水,都是在操作原来那个杯子。外界看到的就是这个杯子的变化。
-
本文详细介绍了C++中的Lambda表达式,包括其定义、捕获规则和使用场景。Lambda表达式是一种匿名函数,允许在函数内部定义可调用的代码块。它可以捕获外部作用域的变量,支持值捕获、引用捕获和显式捕获。Lambda表达式在排序、查找等操作中有着广泛应用,如自定义比较函数。示例展示了如何在不同情况下使用Lambda表达式,包括不使用和使用捕获列表的情况。

被折叠的 条评论
为什么被折叠?



