在介绍C++ lambda表达式之前,我们先了解下谓词的概念
谓词
在C++中,谓词是一种可调用对象(函数、函数对象或Lambda表达式),它返回一个布尔值,用于表示某种条件是否成立。谓词通常用于标准库算法的参数中,例如std::sort、std::find_if等,以确定元素是否符合某个条件。
谓词可以分为一元谓词和多元谓词,取决于它们接受的参数数量。
一元谓词(Unary Predicate):
一元谓词接受一个参数。例如,一个一元谓词可以是一个函数,它接受一个参数并返回一个布尔值,或者是一个Lambda表达式。
// 一元谓词:检查一个整数是否为正数
bool isPositive(int x) {
return x > 0;
}
// 使用一元谓词的例子
std::vector<int> numbers = {1, -2, 3, -4, 5};
auto it = std::find_if(numbers.begin(), numbers.end(), isPositive);
或者使用Lambda表达式:
std::vector<int> numbers = {1, -2, 3, -4, 5};
auto it = std::find_if(numbers.begin(), numbers.end(), [](int x) { return x > 0; });
多元谓词(N-ary Predicate):
我们先给出一个二元谓词(Binary Preficate)的例子。
使用 std::sort 对一个包含自定义结构体(Persion
)的vector
进行排序
#include <algorithm>
#include <iostream>
#include <vector>
struct Person {
std::string name;
int age;
Person(const std::string& n, int a) : name(n), age(a) {}
};
int main() {
std::vector<Person> people = {
{"Alice", 30},
{"Bob", 25},
{"Charlie", 35},
{"David", 28}
};
// 使用多元谓词的例子:按照年龄升序排序
std::sort(people.begin(), people.end(), [](const Person& p1, const Person& p2) {
return p1.age < p2.age;
});
// 输出排序结果
for (const auto& person : people) {
std::cout << person.name << " - " << person.age << " years old" << std::endl;
}
return 0;
}
在这个例子中,我们使用了 std::sort 和一个多元谓词Lambda表达式,该谓词按照 Person 结构体的 age 成员进行升序排序。Lambda表达式接受两个参数,即两个 Person 对象,然后根据它们的年龄进行比较。
在C++中,Lambda表达式可以接受任意数量的参数,因此可以用于实现三元或更高元的谓词。一个三元谓词会接受三个参数,四元谓词会接受四个参数,以此类推。更多元的谓词用法类似,这里不再举例说明。
总结
无论是一元谓词还是多元谓词,它们都用于定义特定条件的可调用对象,以便在标准库算法或其他需要谓词的上下文中使用。这种灵活性使得C++中的算法更加通用,可以适应各种不同的条件。
有了谓词的概念,下面接着介绍Lambda表达式
Lambda表达式
Lambda表达式是C++11引入的一个强大特性,可以编写内联的匿名函数。以下是Lambda表达式的一些需要了解的知识和细节:
1. 基本语法:
Lambda表达式的基本语法包括捕获列表、参数列表、返回类型和函数体。例如:
[capture](parameters) -> return_type {
// function_body
}
capture: 捕获列表,定义了 lambda 函数体外的变量如何在 lambda 内被使用。
parameters: 参数列表,和普通函数的参数列表一样。
return_type: 返回类型。在很多情况下,返回类型可以被编译器推断,因此可以省略。
function_body: 函数体,包含 lambda 函数的代码。
2. 捕获列表(Capture List):
- [] : 不捕获任何外部变量
- [=]:以值传递方式捕获所有外部变量。
- [&]:以引用传递方式捕获所有外部变量。
- [x, y]:以值传递方式捕获指定的变量。
- [&x, &y]:以引用传递方式捕获指定的变量。
- [=, &x]:混合值传递和引用传递方式捕获变量。
3. 参数列表:
Lambda表达式可以包含参数,与普通函数类似。例如:
[](int x, int y) { /* 函数体 */ }
4. 返回类型推导:
Lambda表达式的返回类型可以显式指定,也可以根据返回语句进行自动推导。例如:
显示指定:
[](int x, int y) -> int { return x + y; }
自动推导:
[](int x, int y) { return x + y; }
5. Lambda表达式作为函数参数:
Lambda表达式可以作为函数的参数传递,通常用于算法和STL中的函数。例如:
std::for_each(vec.begin(), vec.end(), [](int x) { /* 函数体 */ });
6. mutable关键字:
如果Lambda表达式需要修改捕获的变量,需要使用mutable关键字。例如:
int x = 0;
auto lambda = [x]() mutable { ++x; };
7. 高级特性
-
可变 Lambda: 使用关键字 mutable 允许您修改按值捕获的变量。
如果Lambda表达式需要修改捕获的变量,需要使用mutable关键字。例如:int x = 0; auto lambda = [x]() mutable { ++x; };
-
泛型 Lambda: 自 C++14 起,可以使用自动类型推断的参数,使得 lambda 可以类似模板函数那样工作。
auto add= [](auto x, auto y) { return x + y; }; std::cout << add(5, 3) << std::endl; // 输出整数 8 std::cout << add(2.5, 3.5) << std::endl; // 输出浮点数 6.0
8. Lambda表达式的限制和注意事项:
Lambda表达式不能包含声明语句。
捕获列表和参数列表可以为空,但{}是必需的。
Lambda表达式使得C++中的函数式编程风格更加灵活和方便,同时提高了代码的可读性和可维护性。Lambda表达式通常在需要定义短小而具体的函数时非常有用,使得代码更加紧凑而不失可读性。