1:定义
- lambda表达式就是一个函数(匿名函数),也就是一个没有函数名的函数。为什么不需要函数名了? 因为我们直接(一次性的)用它,不需要其他地方调用它。
- lambda表达式也叫闭包,闭就是封闭的意思(就是其他地方都不调用它),包就是函数
- lambda表达式其实就是一个函数对象,它内部创建了一个重载()操作符的类
- lambda表达式的简单语法如下:
- [capture] (paramters) ->return value {body},只有[capture] 捕获列表和 {body} 函数体是必选的,其他可选。
2:最简单的一个 lambda表达式(调用)
int main()
{
// [] 代表 lambda表达式的开始
() 代表 函数调用
{} 代表 函数体
// lambda表达式
[] () {}
}
// 上述表达式等价于
void f()
{
}
int main()
{
f();
}
3: lambda表达式调用
#include<iostream>
#include<string>
using namespace std;
int main()
{
// 省略 表达式的 形参和返回值
[] {cout << "hello world"<< endl;};
// 或者这样写
auto lam = [] {cout << "hello world"<< endl;};
lam();
}
4: 返回值
-> int : 代表此匿名函数返回 int
大多数情况下 lambda 表达式的返回值可由编译器猜测出阿里,因此我们不需要指定返回值类型。
int main()
{
// 编译器可以自动推导出 函数体返回值,可以省略 返回int 返回类型
auto lam = []() -> {cout << "hello,world"; return 88;};
// 等价于
auoto lam2 = [](){cout << "hello,world"; return 88;};
auto ret = lam();
cout << ret<< endls; // 打印 88
auto lam3 = [](){cout<< "hello world"; return "test str"};
auto ret3 = lam3();
cout << ret3 << endls; // 打印 test str
}
5: 捕捉变量
变量捕获才是 lambda最卓越的秘方。
- [ ] ----- 不捕获任何变量,这种情况下 lambda 表达式内部不能访问外部变量
- [&] -----以引用方式捕获所有变量
- [=] ------用值得方式捕获所有变量 (也有可能被编译器优化为 const &)
[=, &foo] ----以引用的方式捕获 foo 变量,其他变量通过值方式捕获
[&, foo] ---- 以值方式捕获 foo 变量,其他变量靠引用捕获
[bar] ------以值方式捕获bar变量,不捕获其他变量
[this] ------捕获所在类的this 指针 (在QT中使用的比较多,如此lambda可以通过this方位界面控件的数量。)
int main()
{
int a = 1,b=2,c=3;
auto lam2 = [&,a] ()
{
// a以值得方式捕获,b和c以引用方式捕获
b = 4, c= 5;
a = 6; // error : a是不可修改的左值
// 打印输出:1 4 5
cout<< a << b << c<<enld;
};
lam2();
}
6: lambda 在 STL中算法库中应用
毋庸置疑: lambda表达式最大的一个优势是在 使用 STL中的算法(algorithms)库应用。
案例1:循环打印容器中的数据
vector<string> address = {"1111","222","333","org","www"};
int mian()
{
for_each(address.begin(), address.end(),[](const string& str){
cout<< str << endl;
});
}
案例2: 给数组排序
// 数组代码排序(自己写一个降序接口)
int arr[] = {6,10,8,9,2,5};
bool compare(int& a, int& b) {
// 降序排序
return a>b;
}
std::sort(arr,arr+6 ,compare);
// 给数组排序(lambda表达式)
str::sort(arr,arr+6, [](const int& a, const int& b){
return a>b;
});
// 优化 C++14 支持基类类型推导的泛型
str::sort(arr,arr+6, [](const auto& a, const auto& b){
return a>b;
});
// 打印排序后的数据
std::for_each(begin(arr),end(arr), [](const int& a) {
cout<< "After sort: " << a;
});
7: 创建lambda函数的一个原因是:有些人创建了一个希望接受(lambda函数)参数的函数
- lambda 的引入给我吗带来一种全新的编程体验,它可以让我们把 "function" 当做是“data”一样传递,并且使我们从繁琐的语法中解放出来,更加关注 “算法”本身。
- 新的 std::function 是传递lambda函数的最好方式,不管是传参数还是传返回值
- 以下代码:将lambda表达式作为函数参数传递,程序作用很简单,是从一个地址薄中查找满足条件的地址(匹配字符串或者长度规则)
#include<iostream>
#include<string>
#include<vector>
#include<functional>
#include<algorithm>
using namespace std;
class AddressBook
{
public:
// 提供一个通用的查找方法,以供查询(匹配的地址),这个方法接受一个查找规则的函数作为参数。
std::vector<string> findMatchingAddress(std::function<bool(const string&)> func)
{
std::vector<string> results;
for (auto it = _addresses.begin(),end = _addresses.end();it != end; ++it)
{
// 调用传递到 findMatchingAddresses的函数并检测是否匹配规则
if (func(*it))
{
results.push_back(*it);
}
}
return results;
}
void SetAddress(const std::vector<std::string>& address) {
_addresses = address;
}
private:
std::vector<string> _addresses;
};
// 声明一个全局的 AddressBook对象。
AddressBook global_address_book;
// 查找匹配名字的地址
vector<string> findAddressesFromName(const string& name)
{
return global_address_book.findMatchingAddress(
[&](const string& addr) {
return addr.find(name) != string::npos;
}
);
}
// 查找匹配长度的地址(大于 min_len)
vector<string> findAddressLen(const size_t& min_len) {
return global_address_book.findMatchingAddress(
[&](const string& addr) {
return addr.length()>= min_len;
}
);
}
int main() {
// 初始化 AddressBook 对象的成员 _addresses
vector<string> address{ "china chengdu","china wuhan",
"china guangzhou","japan dongjing","Americal huashengdun"};
global_address_book.SetAddress(address);
// 查找包含china的地址
auto ret = findAddressesFromName("china");
for_each(ret.begin(), ret.end(), [](string& str) {
cout << str << " ";
});
cout << endl;
// 查找长度大于15的地址
auto ret2 = findAddressLen(15);
for_each(ret2.begin(), ret2.end(), [](string& len) {
cout << len << " ";
});
}
请注意看下面这个问题:std::function<> func : 泛型返回值和入参均要和实参对应。