Lambda
ISO C++ 11 标准的一大亮点是引入Lambda表达式,Lambda 表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。
基本语法如下:
|
|
[capture list]
:捕捉列表。捕捉列表总是出现在Lambda函数的开始处。实际上,[]
是Lambda引出符。编译器根据该引出符判断接下来的代码是否是Lambda函数。捕捉列表能够捕捉上下文中的变量以供Lambda函数使用;(parameter list)
:参数列表。与普通函数的参数列表一致。如果不需要参数传递,则可以连同括号“()”一起省略;mutable
:mutable
修饰符。默认情况下,Lambda函数总是一个const
函数,mutable
可以取消其常量性。在使用该修饰符时,参数列表不可省略(即使参数为空);->return-type
:返回类型。用追踪返回类型形式声明函数的返回类型。我们可以在不需要返回值的时候也可以连同符号->
一起省略。此外,在返回类型明确的情况下,也可以省略该部分,让编译器对返回类型进行推导;{function body}
:函数体。内容与普通函数一样,不过除了可以使用参数之外,还可以使用所有捕获的变量。
lamda表达式,与普通函数,最大的不同,在于拥有捕获列表,捕获列表有一下几种形式:
- [] 不截取任何变量
- [&] 截取外部作用域中所有变量,并作为引用在函数体中使用
- [=] 截取外部作用域中所有变量,并拷贝一份在函数体中使用
- [=, &foo] 截取外部作用域中所有变量,并拷贝一份在函数体中使用,但是对foo变量使用引用
- [bar] 截取bar变量并且拷贝一份在函数体重使用,同时不截取其他变量
- [this] 截取当前类中的this指针。如果已经使用了&或者=就默认添加此选项。
int id = 0;
//此时截取了id的值为0,后面调用的时候id为0
//mutable 表明id是可变的,否则编译不通过
auto f = [id]() mutable { cout << "id=" << id << endl; id++};id = 42;
f();// 0
f();//1
f();//2
cout << "after f() id=" << id << endl;//42
lambda的使用:
1. 用于函数参数
#include <iostream>
#include<algorithm>
#include <vector>using namespace std;
template <typename T>
using Vec = vector<T, allocator<T>>;int main()
{
Vec<int> vec{1,2,3,4,5,6,7,8,9};
for_each(vec.begin(),vec.end(),[](int v) { cout << v << endl; });//用作函数参数return 0;
}
2. 使用auto来接收一个lambda表达式
当然我们也可以直接使用C++11里面的新特性function来接收lambda表达式,两者等价的,因为auto是自动类型转换,所以在某些场合使用起来更方便。
#include <iostream>
#include<algorithm>
#include <vector>
#include <functional>
using namespace std;
int main()
{
auto add = [](int a, int b) { return a + b; };
//[=] 截取外部作用域中所有变量,并拷贝一份在函数体中使用
function<int(int, int)> add2 = [=](int a, int b) { return a + b; };
int x = 5, y = 19;
cout << add(x, y) << " " << add2(x,y) << endl;
return 0;
}
3. 使用lambda表达式来实现递归算法
已知f(1)=1,f(2)=2,那么请实现求f(n)=f(n-1)+f(n-2)的值,此处的n>2 :
#include <iostream>
#include<algorithm>
#include <vector>
#include <functional>
using namespace std;
int main()
{
//[&] 截取外部作用域中所有变量,并作为引用在函数体中使用
function<int(int)> recursion = [&recursion](int n)
{
return n < 2 ? 1 : (recursion(n - 1) + recursion(n - 2));
};
cout << "recursion(2):" << recursion(2) << endl;
cout << "recursion(3):" << recursion(3) << endl;
cout << "recursion(4):" << recursion(4) << endl;
return 0;
}
override
override用于明确要重写父类的虚函数上,相当于告诉编译器这个函数就是要重写父类虚函数这样一个意图,让编译器帮忙检查,而没有这个关键字,编译器是不会帮你检查的。
#include <iostream>
using namespace std;
class Base {
public:
virtual void func(int) { cout << "Base::func(int)" << endl; };
};
class Derived : public Base
{
public:
//本意是写重写基类的func,但是函数参数错误,并未实现重写,并且编译器也未有期望的任何提示
void func(float) { cout << "Derived::func(float)" << endl; }
};
class Derived2 : public Base
{
public:
//error C3668: “Derived2::func”: 包含重写说明符“override”的方法没有重写任何基类方法
void func(float) override { cout << "Derived2::func(float)" << endl; }
};
int main()
{
return 0;
}
final
final新增两种功能:(1)、禁止基类被继承,(2)、禁止虚函数被重写;
class Base1 final {};
class Base2
{
public:
virtual void func() final {}
};
//error C3246: “Derived1”: 无法从“Base”继承,因为它已被声明为“final”
class Derived1 : public Base1 {};
class Derived2 : public Base2
{
public:
//error C3248: “Base2::func”: 声明为“final”的函数无法被“Derived2::func”重写
void func() {}
};
以上参考:
- https://www.cnblogs.com/laiyingpeng/p/11603353.html
- https://www.bilibili.com/video/BV11x411Z7zk?p=13
- https://blog.csdn.net/vinson0526/article/details/50962682?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~all~first_rank_v2~rank_v25-2-50962682.nonecase&utm_term=c++%E7%94%A8%E9%80%94%20lambda&spm=1000.2123.3001.4430
- https://blog.csdn.net/qq_34199383/article/details/80469780