C++ 11 Lambda表达式
如何声明Lambda表达式
当在C++11中使用Lambda表达式时,就是创建匿名的内联函数,这在很多情况下可以让我们更方便地编写代码。Lambda表达式在C++11中引入,提供了一种简洁的方法来定义临时函数对象,通常用于在函数中传递行为(函数功能)而不是简单的数据。
下面是Lambda表达式的一般语法:
[capture](parameters) -> return_type {
// Lambda body
}
其中:
- capture 是一个捕获列表,用于指定Lambda表达式中所使用的外部变量。
- parameters 是Lambda表达式的参数列表,类似于普通函数的参数列表。
- return_type 是Lambda表达式的返回类型。
- Lambda body 包含实际的Lambda表达式代码。
以下是一个简单的Lambda表达式示例,它接受两个整数并返回它们的和:
#include <iostream>
int main() {
// Lambda expression that adds two integers
auto add = [](int a, int b) -> int {
return a + b;
};
int result = add(5, 7);
std::cout << "Result: " << result << std::endl;
return 0;
}
如何捕获外部变量
Lambda表达式通过捕获列表(capture list)来捕获外部变量,以便在Lambda表达式内部使用这些变量。捕获列表出现在Lambda表达式的开头,并用方括号 [] 括起来,里面包含捕获的变量。
捕获列表可以有不同的形式,以指定捕获外部变量的方式:
捕获单个变量:
- :通过值捕获变量 x,在Lambda内部创建一个副本,对外部变量的修改不会影响Lambda内的副本。
- [&x]:通过引用捕获变量 x,在Lambda内部直接引用外部变量 x,可以修改外部变量。
捕获多个变量:
- [x, y]:通过值捕获变量 x 和 y。
- [&x, y]:通过引用捕获变量 x,通过值捕获变量 y。
捕获所有变量:
- [=]:通过值捕获所有局部作用域中的变量。
- [&]:通过引用捕获所有局部作用域中的变量。
混合捕获:
- [=, &x]:通过值捕获所有局部作用域中的变量,但通过引用捕获变量 x。
下面是一些示例:
#include <iostream>
int main() {
int x = 10;
int y = 20;
// Capture by value
auto captureByValue = [x, y]() {
std::cout << "Capture by value: x = " << x << ", y = " << y << std::endl;
};
// Capture by reference
auto captureByReference = [&x, &y]() {
x *= 2; // Modifying x inside the lambda
std::cout << "Capture by reference: x = " << x << ", y = " << y << std::endl;
};
// Capture all by value
auto captureAllByValue = [=]() {
std::cout << "Capture all by value: x = " << x << ", y = " << y << std::endl;
};
// Capture all by reference
auto captureAllByReference = [&]() {
x += 5; // Modifying x inside the lambda
std::cout << "Capture all by reference: x = " << x << ", y = " << y << std::endl;
};
captureByValue();
captureByReference();
captureAllByValue();
captureAllByReference();
return 0;
}
通过捕获列表,可以灵活地选择捕获外部变量的方式,以满足不同的需求。但是需要注意的是,捕获的方式会影响Lambda表达式内外变量的交互方式和作用域。
捕获的局部变量作用域有何变化
Lambda表达式捕获的局部变量作用域与传统的函数对象或函数指针稍有不同。Lambda表达式允许你捕获外部变量,并在Lambda表达式内部使用它们,但它们的生命周期和作用域会受到一些限制。
- 按值捕获:通过值捕获外部变量,Lambda表达式会在其内部创建变量的副本。这意味着,即使外部变量在Lambda表达式之后发生更改,Lambda内部的副本仍然保持在捕获时的值。这些捕获的变量在Lambda表达式内部的作用域中存在,超出Lambda表达式作用域后销毁。
- 按引用捕获:通过引用捕获外部变量,Lambda表达式会在其内部直接使用外部变量,而不是创建副本。这使得Lambda表达式内部对引用变量的修改会影响外部变量。
需要注意以下几点:
- 如果使用按值捕获,Lambda内的变量是在捕获时复制的,因此对外部变量的更改不会影响Lambda内的副本。
- 如果使用按引用捕获,Lambda内的变量直接引用外部变量。这意味着你可以在Lambda内部修改捕获的引用变量,这些修改会反映在外部变量上。
- 对于按值捕获的变量,Lambda表达式内的变量将在Lambda表达式作用域结束时销毁。
- 对于按引用捕获的变量,当Lambda表达式在其生命周期内被调用时,捕获的引用仍然有效。
下面是一个示例,演示了不同捕获方式对变量作用域的影响:
#include <iostream>
int main() {
int x = 10;
// Capture by value
auto captureByValue = () {
std::cout << "Capture by value: x = " << x << std::endl;
};
// Capture by reference
auto captureByReference = [&x]() {
std::cout << "Capture by reference: x = " << x << std::endl;
};
x = 20;
captureByValue(); // Output: Capture by value: x = 10
captureByReference(); // Output: Capture by reference: x = 20
return 0;
}
在此示例中,按值捕获的Lambda保留了捕获时的值(10),而按引用捕获的Lambda使用了最新的值(20)。
Lambda表达式的参数列表和普通函数有区别吗
Lambda表达式的参数列表与普通函数的参数列表类似,它定义了Lambda表达式所接受的输入参数。Lambda表达式的参数列表位于捕获列表后面,使用圆括号 () 括起来,可以在其中指定零个或多个参数。
以下是Lambda表达式参数列表的一般形式:
[capture](parameters) -> return_type {
// Lambda body
}
在 parameters 部分,你可以列出Lambda表达式接受的参数,与普通函数参数的定义方式相同。参数之间用逗号 , 分隔。
以下是一些Lambda表达式的参数列表示例:
无参数的Lambda表达式:
[]() { // Lambda body }
带有一个参数的Lambda表达式:
[](int x) { // Lambda body }
带有多个参数的Lambda表达式:
[](int x, double y) { // Lambda body }
按值捕获外部变量并带参数的Lambda表达式:
(int y) { // Lambda body using x and y }
按引用捕获外部变量并带参数的Lambda表达式:
[&x](int y) { // Lambda body using x (by reference) and y }
Lambda表达式的参数列表允许你定义Lambda在调用时接受的输入数据。这些参数可以在Lambda表达式的主体内使用,用于执行特定的操作。与函数类似,Lambda表达式的参数也可以有不同的类型,并且可以在调用Lambda时传递相应的参数值。
Lambda表达式省略
Lambda表达式的语法相对简单,但在某些情况下你可以省略一些部分,使代码更加简洁。以下是Lambda表达式的一些可能的省略情况:
省略返回类型 :Lambda表达式的返回类型可以自动推断出来,因此你可以省略返回类型的显式声明。例如:
auto lambda = [](int x, int y) { return x + y; };
省略参数列表的类型声明: 如果Lambda表达式的参数列表中的参数类型是显而易见的,你可以省略类型声明,使用 auto 关键字来进行自动类型推断。例如:
auto lambda = [](auto x, auto y) { return x + y; };
这使得Lambda表达式更加通用,可以接受不同类型的参数。
省略参数列表和返回类型: 如果Lambda表达式非常简单,参数列表和返回类型都可以省略,使代码更加紧凑。例如:
auto lambda = [] { return "Hello, Lambda!"; };
省略捕获列表 :如果Lambda表达式不需要访问外部变量,你可以省略捕获列表。
auto lambda = [] { // Lambda body };
请注意,虽然省略某些部分可以使Lambda表达式更加简洁,但有时显式声明类型和其他信息可以使代码更加清晰和可读。在选择省略哪些部分时,需要根据代码的上下文和可读性权衡利弊。
需要注意的是,这些省略特性通常在C++14及以后的标准中得到更好的支持和扩展,C++11中的Lambda表达式相对较为基础。
本文系作者 @何健源 原创发布在思维代码站点。未经许可,禁止转载。
暂无评论数据