面试题目
你怎么用lambda表达式
匿名函数。当我有一个功能,只有一个地方被调用,但是函数很简单,就用lambda表达式
lambda表达式是怎么返回的呢?
使用auto接收,使用尾值返回类型的方式设置lambda表达式的返回类型
int main(){
auto lam == [](int elem)-> int {return elem};
cout << lam(3);
}
正文
lambda入门
一个函数内部不能包含另一个函数,lamba表达式解决函数此问题:函数表达式
最简单的lamba表达式
#include <iostream>
using namespace std;
void main()
{
[] {cout << "hello"; cout << "world"; }(); //匿名lamba表达式,()表示调用,{}表示函数体,
cin.get();
}
lamba表达式与函数指针
定义一个函数指针,然后调用
#include <iostream>
using namespace std;
void main()
{
auto fun = [] {cout << "hell"; }; //fun是一个函数指针,指向一个函数
fun(); //调用
cin.get();
}
lamba的传入参数
- 与一般函数一样,有副本机制
#include <iostream>
using namespace std;
void main()
{
int num = 100;
auto funrc = [](int num) {num = 5, cout << num << endl; };
cout << "main:" << num << endl; //100
funrc(num); //5 //函数副本机制
cout << "main:" << num << endl; //100
cin.get();
}
lamba表达式的返回值
#include <iostream>
using namespace std;
int main()
{
auto fun1 = [](double a, double b) {return a + b; }; //有名lamba表达式,auto自动推理类型
cout << fun1(11, 11.1) << endl;
auto fun2 = [](double a, double b)->int {return a + b; }; //->指定返回值类型
cout << fun2(10, 19.1) << endl;
auto fun3 = [](double a, double b)->decltype(a + b) {return a + b; }; //->指定返回值类型
cout << fun3(10, 10) << endl;
// cout << typeid(fun1).name() << endl; //class <lambda_随机数>
// cout << (void*)fun1 << endl; //lamba表达式是内联展开的,无法取出地址
cin.get();
}
总结:
- lamba表达式是为了解决函数怀孕问题
- lamba表达式是内联展开的,无法取出地址
- lamba本质上是一个类
- lamba()的传入参数有副本机制
auto自动推理数据类型
#include <iostream>
using namespace std;
void main()
{
[](auto a, auto b){cout << a + b << endl; }(10, 11); //auto可以推理数据类型
[](auto a, auto b){cout << a + b << endl; }(10.8, 11);
[](auto a = 0 , auto b = 0 ){cout << a + b << endl; }(10, 11);
cin.get();
}
lambda高级
lamba表达式如何捕获外部变量
- &表示以引用的方式捕获外部变量,因此可以直接对外部变量内存进行读写
- =表示以值传递的方式捕获外部变量,因此不能改变外部变量,matable是对=的补充
- 必须显示的捕获,没有隐式的捕获
#include <iostream>
using namespace std;
int main()
{
int num1 = 100;
int num2 = 99;
cout << "原本: "<< &num1 <<"[" <<num1 << "], "<< &num2 <<"[" << num2 << "]"<< endl;
[=]() {
cout << "[=]() 可以捕获外部变量生成一个副本,这个副本是只读的: "<< &num1 <<"[" <<num1 << "], "<< &num2 <<"[" << num2 << "](副本是只读的)\n";
}(); //=只能读不能写 ---> 两个地址不同,说明是不同的内存,=的操作是复制原本给lamba表达式
// [=]() {num1 = 22, cout << num1 << num2 << endl; }();// C3491 “num1” : 无法在非可变 lambda 中修改通过复制捕获
[=]()mutable {
num1 = 666; num2 = 77;
cout <<"[=]()mutable 可以使用mutable生成一个副本,这个副本是可读可写的: " << &num1 <<"[" <<num1 << "], "<< &num2 <<"[" << num2 << "](修改副本不会影响原本:mutalbe是一个声明,表示操作副本,可以看作是=的补充)\n";
}(); //666999mutable改变副本 ----> mutalbe是一个声明,表示操作副本,可以看作是=的补充
cout << "原本: "<< &num1 <<"[" <<num1 << "], "<< &num2 <<"[" << num2 << "]"<< endl;
num1 = 100, num2 = 99;
[&]() {
num1 = 11, num2 = 66, cout << "[&] 可以捕获并读写外部变量的原本 "<< &num1 <<"[" <<num1 << "], "<< &num2 <<"[" << num2 << "](&地址相同,表示以引用的方式捕获外部变量,操作同一块内存,因此可以改写原本)\n";
}(); //1199 &表示读写外部变量,改变原本 ----> &地址相同,表示以引用的方式捕获外部变量,操作同一块内存,因此可以改写原本
cout << "原本: "<< &num1 <<"[" <<num1 << "], "<< &num2 <<"[" << num2 << "]"<< endl;
num1 = 100, num2 = 99;
}
单独改变捕获某一个值
#include <iostream>
using namespace std;
int main()
{
int a = 10;
int b = 9;
int c = 15;
//[&a]() {a = 100; cout << a << b << c << endl; }(); //无法隐式捕获“b/c”,因为尚未指定默认捕获模式, 封闭函数局部变量不能在 lambda 体中引用,除非其位于捕获列表中
[&a, b, c]() {a = 100; cout << " " <<a << " " << b << " " << c << " " << endl; }(); //可以改变a的原本
cout << "原本: "<< a << " " << b << " " << c << " " << endl;
a = 10; b = 9; c = 15;
[a, b, c]()mutable {a = 999; b = 333; cout << " " <<a << " "<< b << " " << c << "\n"; }(); //999 333 15
cout << "原本: "<< a << " " << b << " " << c << " " << endl;
//[]()mutable {a = 999; b = 333; cout << a << " " << b << " " << c; }(); //封闭函数局部变量不能在 lambda 体中引用,除非其位于捕获列表中 Cpp.cpp e : \C++\Cpp.cpp\Cpp.cpp\类型转换.cpp 15
}
lamba表达式与数组
#include <iostream>
#include <array>
#include <algorithm>
using namespace std;
void main()
{
array<int, 10>myint{ 1, 2, 3, 4, 5, 6, 7 };
for_each(myint.begin(), myint.end(), [](int num) {cout << num << " "; }); //显示 1, 2, 3, 4, 5, 6, 7 0 0 0
cout << "\n";
for_each(myint.begin(), myint.end(), [](int num) {num += 1, cout << num << " "; }); //修改副本,函数传参副本机制,因此修改的是副本
cout << "\n";
for_each(myint.begin(), myint.end(), [](int num) {cout << num << " "; }); //显示 1, 2, 3, 4, 5, 6, 7 0 0 0
cout << "\n *******************\n" ;
for_each(myint.begin(), myint.end(), [](int &num) {num += 1, cout << num << " "; }); //修改原本,引用原本,对原本进行操作,因此会修改原本
cout << "\n";
for_each(myint.begin(), myint.end(), [](int num) {cout << num << " "; }); //显示,2,3,4,5,6,7,8,1,1,1
cin.get();
}
总结:
- 函数传参如果是值传递,那么副本机制修改副本;如果是引用传参,那么操作原本
- lamba表达式是为了解决代码内嵌问题
- [](){}()匿名lamba表达式
- for_each常常用来遍历容器,比如数组
- array<int, n>{0};是CPP风格的数组
- lamba表达式中[=]表示值捕获外部遍历,[&]表示引用捕获。
--