C++中的Lambda表达式
定义:
在C++中,lambda表达式(也叫匿名函数)是一种可以在代码中定义匿名函数对象的便捷方式。
lambda表达式的基本形式是:
capture list -> return_type { function body } 。
1)[capture list] 是捕获列表,用于指定lambda表达式所在作用域中的变量如何被捕获(可以是值传递或者引用传递),例如 [&] 表示以引用方式捕获所有外部变量, [=] 表示以值的方式捕获所有外部变量。
2)(parameters) 是参数列表,和普通函数的参数列表类似,用于传递参数给lambda函数。如果没有参数,可以写为空括号 () 。
3)-> return_type 是返回值类型部分,用于指定lambda表达式返回值的类型。如果可以自动推断返回类型,这部分可以省略。
4){ function body } 是函数体,包含了lambda表达式要执行的语句。
例如,有一个 vector 存放整数,我们可以使用lambda表达式来进行排序:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numbers = {5, 2, 8, 1, 9};
std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
return a < b;
});
for (int num : numbers) {
std::cout << num << " ";
}
return 0;
}
在这个例子中, [](int a, int b) { return a < b; } 就是一个lambda表达式,作为 std::sort 函数的比较函数,用来指定排序规则。
作用:
1.作为回调函数
许多C++标准库算法需要回调函数来指定操作。比如 std::for_each ,它会对序列中的每个元素执行一个操作,这个操作就可以用lambda表达式来定义。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
std::for_each(v.begin(), v.end(), [](int i) {
std::cout << i * 2 << " ";
});
return 0;
}
在这个例子中, lambda 表达式 [](int i) { std::cout
2.用于排序和比较操作
在使用 std::sort 等函数时,可以用lambda表达式定义比较规则。
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> numbers = {4, 2, 7, 1, 9};
std::sort(numbers.begin(), numbers.end(), [](int a, int b) {
return a > b;
});
for (int num : numbers) {
std::cout << num << " ";
}
return 0;
}
这里的lambda表达式 [](int a, int b) { return a > b; } 定义了从大到小的排序规则。
3)事件处理
在一些简单的事件驱动编程场景中,lambda表达式可以作为事件处理器。虽然C++不是主要用于事件驱动编程的语言,但在简单的图形界面库或者简单的异步编程场景下可以使用。
#include <iostream>
#include <functional>
class Button {
public:
std::function<void()> onClick;
};
int main() {
Button button;
button.onClick = {
std::cout << "Button Clicked!" << " ";
};
button.onClick();
return 0;
}
这个例子简单模拟了一个按钮点击事件, lambda 表达式 { std::cout
捕获变量的类型:
1.局部自动变量(栈变量)
这是最常见的情况。例如在一个函数内部定义的普通变量。
#include <iostream>
int main() {
int num = 10;
// 捕获局部自动变量num
auto lambda = num {
std::cout << num << std::endl;
};
lambda();
return 0;
}
在这个例子中,lambda表达式捕获了函数 main 中的局部变量 num 。
2.静态局部变量
可以捕获在函数内定义的静态变量。
#include <iostream>
int main() {
static int static_num = 20;
auto lambda = static_num {
std::cout << static_num << std::endl;
};
lambda();
return 0;
}
这里lambda表达式捕获了静态局部变量 static_num 。
3.类成员变量(在类的成员函数中)
当lambda表达式在类的成员函数中定义时,可以捕获类的成员变量。不过要注意捕获方式和成员访问权限等问题。
#include <iostream>
class MyClass {
public:
int member_var = 30;
void func() {
// 捕获类成员变量member_var
auto lambda = this {
std::cout << this->member_var << std::endl;
};
lambda();
}
};
int main() {
MyClass obj;
obj.func();
return 0;
}
在这个类的成员函数 func 中,lambda表达式通过 [this] 捕获了类 MyClass 的成员变量 member_var 。
捕获方式:
1.按值捕获([=])
会捕获lambda表达式所在作用域的所有变量,并且以副本的形式使用这些变量。
#include <iostream>
int main() {
int num = 10;
auto lambda = = {
std::cout << num << std::endl;
};
lambda();
num = 20;
lambda();
return 0;
}
在这个例子中,lambda表达式按值捕获了 num 变量。即使在调用lambda表达式后修改 num 的值,lambda表达式内部使用的 num 值依旧是捕获时的值(10)。
2.按引用捕获([&])
捕获lambda表达式所在作用域的所有变量的引用,对捕获变量的修改会影响外部变量。
#include <iostream>
int main() {
int num = 10;
auto lambda = & {
std::cout << num << std::endl;
num = 20;
};
lambda();
std::cout << num << std::endl;
return 0;
}
这里lambda表达式按引用捕获 num ,在lambda表达式内部修改 num 的值,外部的 num 变量也会随之改变。
3.混合捕获([=, &var]或者[&, =var])
可以指定部分变量按值捕获,部分变量按引用捕获。例如 [=, &num] 表示除了 num 按引用捕获外,其他变量按值捕获。
#include <iostream>
int main() {
int num1 = 10;
int num2 = 20;
auto lambda = =, &num1 {
std::cout << num1 << " " << num2 << std::endl;
num1 = 30;
};
lambda();
std::cout << num1 << std::endl;
return 0;
}
在这个lambda表达式中, num1 按引用捕获, num2 按值捕获。修改 num1 的值会影响外部变量 num1 的值。
4.捕获特定变量([var])
只捕获指定的变量,并且以副本形式捕获。
#include <iostream>
int main() {
int a = 5, b = 10;
auto lambda = a {
std::cout << a << std::endl;
};
lambda();
return 0;
}
此lambda表达式仅捕获 a 变量, b 变量未被捕获,在lambda表达式内部无法访问 b 。