什么是λ演算
首先,这个λ演算是非常牛逼的一个东西,可以看一下维基百科——λ的介绍
C++ 适用 λ 表达式
众所周知,如果一个工程中用了很多函数名,最终会导致命名污染。
不妨假设如下场景,如果你有一个函数,需要重复写一段代码,你会选择将这段代码封装成另一个函数FUN。但是,一个函数就需要一个名字,你封装成的另一个函数FUN就需要一个名字,但是这个FUN函数,你在其他地方又用不到了,那么就可以尝试适用匿名函数来实现了。
简单用法
int function() {
auto add = [](int a, int b){
if(a % 2) return a+b;
return a;
};
cout << add(3,4);
return 0;
}
// 上面这个结果就会输出 7
// 用到这里你会发现lambda没有什么牛逼之处
// 但是,如果你不想这个add函数在外部用到,而仅仅是function函数中使用
// 那么它将带来很大的遍历,你不需要考虑如何去命名
细节用法
可能不太理解为什么像上述写法这么写 [](){},这个为什么构成lambda表达式
-
[]部分:这里是表示捕获部分,为什么需要捕获呢?因为
add函数也许需要用到function函数中的东西。有人发出疑问?不是可以传参吗?
但是,传参造成了很多不必要的麻烦,如:你需要先声明传参类型,然后你一般需要传引用,最后导致参数列表变得冗长
而
[]很好的解决这个问题[]:为空,那么就是不捕获任何参数,就是lambda表达式中不能使用外部的变量[=]:值捕获,并且捕获所有变量[&]:引用捕获,也是捕获所有变量[this]:捕获当前的类的指针[a]:只捕获a的值[&a]:捕获a的引用[=, &a, &b]:除了a,b引用传递外,其余的值传递[&, a, b]:除了a,b值传递外,其余的引用传递
-
()部分:这里是参数列表,和普通函数一样,值传递和引用传递都可以 -
{}部分:代码块
除此之外,还和普通函数一样,有说明符和返回值的约束。
// 说明符的介绍
auto f = [&]() mutable
{
return 1;
}
mutable:允许 函数体 修改各个复制捕获的对象,以及调用其非const成员函数;constexpr:显式指定函数调用运算符为constexpr函数。此说明符不存在时,若函数调用运算符恰好满足针对constexpr函数的所有要求,则它也会是constexpr; (C++17 起)consteval:指定函数调用运算符为立即函数。不能同时使用consteval和constexpr。(C++20 起)
// 返回值介绍
// 限制返回 int
auto f = [&]() -> int
{
return 1;
}
补充说明
有人发现了,前面都是使用auto关键词声明的,那么可不可以声明为具体类型了,答案是也可以的。既然是匿名函数,肯定没有固定的typeid,经过测试,那怕完全相同的两个函数,其typeid都是不一样的。就像int a = 1; int b = 1;中a,b不是用一个东西,仅仅是两个变量的值一样,但是a,b的typeid是一样的。auto f1 = [](){}; auto f2 = [](){};中,f1, f2他们仅仅是地址对应的值相同而已,都是只执行了[](){}这个函数。
但是,前面说可以声明为具体类型,那么,该怎么实现呢?答案是:函数指针
- 注意,这里的返回值
-> int不能省略 - 而且,如果下述实现,是有
typeid(f)==typeid(g) - 并且还有
typeid(f) == typeid(g) == typeid(h) - 至于这个为什么呢?我也没有想明白这些,之后再努力看看才行。
int (*f)() = []() -> int {return 1;};
int (*g)() = []() -> int {return 1;};
int a(){return 1;}
int (*h)() = a; // 也可写做 int(*h)() = &a; 因为函数名本来就是地址