(C++11/C++14新特性)C++中的Lambda表达式——捕获方式和参数?值捕获和引用捕获?泛型Lambda和普通Lambda?
作者:求一个demo
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处
内容通俗易懂,没有废话,文章最后是面试常问内容(建议通过标题目录学习)
废话不多说,我们直接开始------>>>>>>
一、Lambda表达式
Lambda表达式是C++11引入的一种匿名函数特性,允许你在需要函数的地方内联定义函数,不需要单独声明和定义命名函数。
1、基本语法
(1)Lambda表达书基本组成部分:
[capture](parameters) -> return_type {
// 函数体
}
①capture:捕获子句,指定哪些外部变量可以在Lambda体内使用。
②parameters:参数列表(可选)。
③return_type:返回类型(可选,通常可以自动推导),这两种情况可以不写(无返回值;返回值可以被编译器推导)。
④函数体body:用于编写函数逻辑的地方。
(2)Lambda表达式的底层是如何实现的?
①编译器生成一个匿名类。
②捕获的变量称为该类的成员变量
③重载了operator()。
2、捕获子句(捕获变量的几种方式)
捕获子句(捕获列表)决定了Lambda表达式如何访问外部变量:
①[]:不捕获任何外部变量。
②[=]:以值捕获所有外部变量(包括this指针)。
③[&]:以引用捕获所有外部变量。
④[a,&b]:混合捕获,a以值捕获,b以引用捕获。
⑤[this]:捕获当前类的this指针。
⑥[=,&x]:默认以值捕获,但x以引用捕获。
⑦[&,x]:默认以引用捕获,但x以值捕获。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
int x = 10;
int y = 20;
// 简单的lambda表达式
auto print = []() { cout << "Hello Lambda!\n"; };//
print();//调用lambda这个函数
// 带参数的lambda
auto add = [](int a, int b) { return a + b; };
cout << add(5, 3) << "\n"; // 输出8
// 捕获外部变量
auto capture = [x, &y]() {
cout << "x: " << x << ", y: " << y << "\n";
y++; // 可以修改y,因为它是引用捕获
// x++; // 错误!x是值捕获,不能在函数内部修改
};
capture();
cout << "y after capture: " << y << "\n"; // y被修改
// 在STL算法中使用lambda
vector<int> nums = {1, 5, 3, 4, 2};
sort(nums.begin(), nums.end(), [](int a, int b) {
return a > b; // 降序排序
});
for (int n : nums) {
cout << n << " ";
}
cout << "\n";
// 可变lambda (允许修改值捕获的变量)
auto mutable_lambda = [x]() mutable {
x++; // 可以修改,因为是mutable
cout << "Inside mutable lambda: " << x << "\n";
};
mutable_lambda();
cout << "Outside: " << x << "\n"; // 原x不变
return 0;
}
3、按值捕获和按引用捕获
(1)按值捕获:只可以输出内容,不可以对内容进行修改,捕捉列表中的变量为只读,是原变量的一份拷贝。如果按值捕获,并且想要修改拷贝的值,可以使用mutable关键字进行修饰(修改const修饰的变量也可以用mutable)。
auto mutable_lambda = [x]() mutable {
x++; // 可以修改,因为是mutable
cout << "Inside mutable lambda: " << x << "\n";
};
(2)按引用捕获:获得该变量的引用,可以对该变量进行任何操作。
4、返回类型
大多是情况下,编译器可以自动推导Lambda的返回值。但当函数体包含多个return语句且类型不同时,需要显示指定返回类型:
auto lambda = [](int x) -> double {//接收int类型参数,返回值类型为double类型(不写 -> double,编译器自动推导返回int类型)。
if (x > 0) return 1.5;
else return 2;//这里会隐式转换为double
};
auto lambda = [](int a, double b) { return a + b; };//返回更高精度的类型(double),此例属于普通lambda,int可以隐式转换为double。
二、区别(泛型Lambda表达式和普通Lambda表达式)
1、参数类型声明方式
(1)普通Lambda(C++11):必须显示指定每个参数具体类型。
auto lambda = [](int a, double b) { return a + b; };
(2)泛型Lambda(C++14):使用auto作为参数类型,编译器会根据实际调用推导类型。
auto lambda = [](auto a, auto b) { return a + b; };
2、模板机制
(1)普通Lambda(C++11)
①相当于一个普通函数对象,参数类型固定。
②如果需要对不同类型操作,需要定义多个Lambda。
(2)泛型Lambda(C++14)
①相当于一个函数模板(使用auto定义参数类型)。
②编译器会为每种调用参数组合生成相应的实例,例如可处理int+double等组合。
3、使用场景
(1)普通Lambda(C++11)
①参数类型明确且固定的情况。
②需要明确控制参数类型时。
(2)泛型Lambda(C++14)
①需要处理多种类型参数的时候。
②编写更通用的代码,特别是模板代码中。
③避免为不同的类型重复编写相似的Lambda。
4、实现原理
(1)普通Lambda(C++11):编译器生成一个具有固定参数类型的函数调用运算符。
(2)泛型Lambda(C++14):编译器生成一个模板化的函数调用运算符。
5、总结
①参数类型:普通Lambda必须显示指定;泛型Lambda可用auto自动推导。
②灵活性:普通Lambda只能处理固定类型;泛型Lambda可处理多种类型。
③实现方式:普通Lambda是普通函数对象;泛型Lambda是模板化函数对象。
④代码复用:普通Lambda需要为不同类型编写多个Lambda;泛型Lambda 可以一个Lambda处理多种类型。
⑤典型应用:普通Lambda适用于类型明确的简单操作;泛型Lambda适用于通用算法、模板代码。
三、校招面试常问内容
1、什么是Lambda表达式?优点是什么?
(1)什么是Lambda:匿名函数,可以在需要函数的地方内联定义。
(2)优点:代码简洁,捕获上下文变量方便。
2、Lambda表达式基本语法?
[capture](parameters) -> return_type { body }
捕获列表、参数列表、返回类型(可省略)、函数体。
3、Lambda的捕获列表有哪些?有什么区别?
①[]:不捕获任何外部变量。
②[=]:以值捕获所有外部变量(包括this指针)。
③[&]:以引用捕获所有外部变量。
④[a,&b]:混合捕获,a以值捕获,b以引用捕获。
⑤[this]:捕获当前类的this指针。
⑥[=,&x]:默认以值捕获,但x以引用捕获。
⑦[&,x]:默认以引用捕获,但x以值捕获。
4、值捕获和引用捕获的区别?
①值捕获:创建时拷贝变量,内部不能修改(使用mutable进行内部修改,不影响外部)。
②引用捕获:直接使用外部变量,内部修改会影响外部。
5、普通Lambda和泛型Lambda的区别?
①参数类型:普通Lambda必须显示指定;泛型Lambda可用auto自动推导。
②灵活性:普通Lambda只能处理固定类型;泛型Lambda可处理多种类型。
③实现方式:普通Lambda是普通函数对象;泛型Lambda是模板化函数对象。
④代码复用:普通Lambda需要为不同类型编写多个Lambda;泛型Lambda 可以一个Lambda处理多种类型。
⑤典型应用:普通Lambda适用于类型明确的简单操作;泛型Lambda适用于通用算法、模板代码。
6、Lambda表达式的底层是如何实现的?
①编译器生成一个匿名类。
②捕获的变量称为该类的成员变量
③重载了operator()。
7、Lambda和函数指针的区别?
①Lambda可以有状态(捕获变量),函数指针无状态。
②Lambda更灵活,可内联定义。
③无捕获的Lambda可(隐式)转换为函数指针。
// 定义一个函数指针类型
using FuncPtr = int(*)(int, int);
int main() {
// 无捕获的 Lambda 表达式
auto lambda = [](int a, int b) {
return a + b;
};
// 将 Lambda 表达式转换为函数指针
FuncPtr funcPtr = lambda;
// 使用函数指针调用
int result = funcPtr(3, 5);
cout << "Result: " << result << endl;
return 0;
}
8、如何在类成员函数中使用Lambda?
捕获this指针访问成员。
class MyClass {
void func() {
auto lambda = [this](){ this->memberFunc(); };
}
};
最后,如有不足和错误的地方,期待私信指正!