C++ Lambda表达式允许我们定义匿名函数对象,它既可以内联使用,也可以作为参数传递。它以更方便简洁的方式创建匿名函数,因为我们不需要在单独的类或结构中重载()运算符。
文章目录
- [1 基本Lambda语法](#1 基本Lambda语法)
- [2 Lambda函数捕获语法](#2 Lambda函数捕获语法)
-
- [2.1 值捕获](#2.1 值捕获)
- [2.2 引用捕获](#2.2 引用捕获)
- [3 STL中将Lambda函数用作参数](#3 STL中将Lambda函数用作参数)
1 基本Lambda语法
一个基本的Lambda表达式可以是这样的:
auto greet = []() {
// lambda function body
};
其中:
[]
:表示lambda表达式的开始()
:参数列表,类似于普通函数的()运算符
这里auto
关键字来自动推断lambda表达式的返回类型。上面的代码等价于:
void greet() {
// function body
}
所以就像普通函数一样,我们可以直接调用greet()
。
例:基本Lambda函数
#include <iostream>
using namespace std;
int main() {
// create a lambda function that prints "Hello World!"
auto greet = []() {
cout << "Hello World!";
};
// call lambda function
greet();
return 0;
}
创建了lambda函数并将其分配给一个名为greet
的变量,然后使用greet
变量和()
运算符调用lambda函数。
例:带参数的Lambda函数
#include <iostream>
using namespace std;
int main() {
auto add = [] (int a, int b) {
cout << "Sum = " << a + b;
};
// call the lambda function
add(100, 78);
return 0;
}
上面的Lambda函数等于:
void add(int a, int b) {
cout << "Sum = " << a + b;
}
例:带返回值的Lambda函数
编译器可以根据返回语句隐式推断出Lambda表达式的返回类型。
auto add = [] (int a, int b) {
// always returns an 'int'
return a + b;
};
在上面的例子中,我们没有明确地定义Lambda函数的返回类型。这是因为只有一个return
语句,它总是返回一个整数值。
但是如果有多个return
语句,必须显式地定义类型。
auto operation = [] (int a, int b, string op) -> double {
if (op == "sum") {
// returns integer value
return a + b;
}
else {
// returns double value
return (a + b) / 2.0;
}
};
上面的代码 ->double
明确地将返回类型定义为 double。因此,无论各种return
语句返回什么类型的值,它们都会被显式转换为double类型。
2 Lambda函数捕获语法
默认情况下,Lambda函数不能访问封闭函数(包含Lambda表达式的函数)的变量。为了访问这些变量,我们使用捕获子句。
2.1 值捕获
这类似于按值调用函数,在这种情况下,Lambda表达式创建时会拷贝实际值,所以原变量的值是无法修改的。
int num_main = 100;
// get access to num_main from the enclosing function
auto my_lambda = [num_main] () {
cout << num_main;
};
在这里, num_main
允许Lambda访问num_main
变量。完整例子:
#include<iostream>
using namespace std;
int main() {
int initial_sum = 100;
// capture initial_sum by value
auto add_to_sum = [initial_sum] (int num) {
// here inital_sum = 100 from local scope
return initial_sum + num;
};
int final_sum = add_to_sum(78);
cout << "100 + 78 = " << final_sum;
return 0;
}
假设我们想按值捕获多个变量:
auto my_lambda = [a, b, c, d, e] (){
// lambda body
}
这样就显得很冗长,我们可以隐式按值捕获所有变量:
auto my_lambda = [=] (){
// lambda body
}
这里的[=]
表示封闭函数内的所有值都被捕获。
2.2 引用捕获
这类似于按引用调用函数,在这种情况下,Lambda表达式可以访问变量的地址。
int num_main = 100;
// access the address of num_main variable
auto my_lambda = [&num_main] () {
num_main = 900;
};
完整例子:
#include <iostream>
using namespace std;
int main() {
int num = 0;
cout << "Initially, num = " << num << endl;
// [&num] captures num by reference
auto increment_by_one = [&num] () {
cout << "Incrementing num by 1.\n";
num++;
};
// invoke lambda function
increment_by_one();
cout << "Now, num = " << num << endl;
return 0;
}
和按值捕获类似,如果要按引用捕获封闭函数中的所有变量 ,可以用[&]
:
auto my_lambda = [&] (){
// lambda body
}
3 STL中将Lambda函数用作参数
来看一个求vector
元素中的偶数个数的例子:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
// initialize vector of integers
vector<int> nums = {1, 2, 3, 4, 5, 8, 10, 12};
int even_count = count_if(nums.begin(), nums.end(), [](int num) {
return num % 2 == 0;
});
cout << "There are " << even_count << " even numbers.";
return 0;
}
这里的count_if
是<algorithm>
中的一个函数,用于对指定范围内的元素执行某种条件测试,并返回满足该条件的元素数量。函数原型如下:
template< class InputIt, class UnaryPredicate >
int count_if( InputIt first, InputIt last, UnaryPredicate p );
其中:
first
和last
:起始和结束迭代器p
:一元谓词,用于测试每个元素是否满足某个条件
函数会遍历从first
到last
的元素,并对每个元素调用谓词p
。如果谓词对于某个元素返回true
,则count_if
函数会增加计数器。最后,函数返回满足谓词的元素数量。
现在再回来看:
int even_count = count_if(nums.begin(), nums.end(), [](int num) {
return num % 2 == 0;
});
这里Lambda表达式作为count_if
的第三个参数,接受整数num
,如果num
是偶数,则返回true。
- 这里不需要写返回值,
auto
也不用写,编译器会自动推断。
上面的例子就等价于:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool isEven(int num) {
return num % 2 == 0;
}
int main() {
vector<int> nums = {1, 2, 3, 4, 5, 8, 10, 12};
int even_count = count_if(nums.begin(), nums.end(), isEven);
cout << "There are " << even_count << " even numbers.";
return 0;
}