目录
1 定义
可以用于不同类型的元素和多种容器类型的算法,实现了一些经典算法的公共接口。
2 相关头文件
在标准库中:
algorithm
头文件:定义了大多数算法numeric
头文件:定义了一组数值泛型算法
3 概述
通常,算法遍历某一个范围(输入范围)内的元素,并对其中每个元素进行一些处理。
输入范围一般由两个迭代器指定,第一个指向要处理的第一个元素,第二个指向要处理的最后一个元素之后的位置。
迭代器的使用,令算法不依赖于容器,但算法依赖于元素类型的操作。
即访问元素可以通过迭代器解引用运算符实现,但算法通常会使用元素类型上的操作。
算法不会直接添加或删除元素。
4 向算法传递函数
4.1 谓词(predicate)
谓词是一个可调用的表达式,其返回一个能用作条件的值。
- 一元谓词:只接受 1 个参数
- 二元谓词:接受 2 个参数
谓词可以是函数指针,或者直接是函数名。
4.2 lambda 表达式
一个可调用的代码单元,可理解为一个未命名的内联函数。同函数类似,具有一个返回类型、一个参数列表和一个函数体。
lambda 表达式可以定义在函数内部。
lambda 表达式可以用作算法的谓词,并且借用捕获列表实现传递多于 2 个参数。
4.2.1 格式
[capture_list] (parameter_list) -> return_type {function_body}
- capture_list:捕获列表,lambda 所在函数中定义的局部变量的列表,通常为空;
- parameter_list:参数列表
- return_type:返回类型,lambda 必须使用尾置返回
- function_body:函数体
参数列表、返回类型可省略,但必须有捕获列表、函数体。
lambda 的形参不能有默认参数。——《C++ Primer》(第5版)
注:从 C++14 标准开始允许有默认参数。
如果 lambda 的函数包含任一
return
语句之外的内容,且未指定返回类型,则返回void
。——《C++ Primer》(第5版)
注:有编译器(如 MinGW64)不遵守此标准。
4.2.2 捕获列表
定义 lambda 时,可以认为是生成了一个未命名类,故向函数传递 lambda 可以看作是传递的参数是未命名类的未命名对象。
类似地,捕获变量是 lambda 的数据成员,在 lambda 定义时初始化。故一般被捕获的变量的值在 lambda 创建时拷贝,并且不随 lambda 所在函数的变量变化而变化,即为值捕获。
要使被捕获的变量的值随 lambda 所在函数的变量变化而变化,应在捕获列表中使用变量的引用,即为引用捕获。
尽量减少捕获变量,尽量避免捕获指针或引用。
可以不在捕获列表中列出所捕获的变量,由编译器根据 lambda 的函数体自行推断,即隐式捕获。但此时还应指示使用值捕获还是引用捕获。
捕获列表 | 解释 |
---|---|
[] | 空列表。lambda 不使用所在函数中的变量。 |
[identifier_list] | 捕获变量之间以逗号分隔,变量名前不加 & 则为值捕获,变量名前加 & 则为引用捕获。 |
[=, identifier_list] | 隐式捕获。默认为值捕获。= 后可以为空,或者列出使用引用捕获的变量(变量名前加 &)。 |
[&, identifier_list] | 隐式捕获。默认为引用捕获。& 后可以为空,或者列出使用值捕获的变量(变量名前不加 &)。 |
默认,lambda 不会改变值捕获的变量,若要改变,需在参数列表尾加上关键字 mutable
,故可变 lambda 不能省略参数列表。
4.3 参数绑定
由于算法的谓词存在参数个数的限制,因此定义普通函数作谓词的方法受到限制,其参数个数有限。而 lambda 表达式因可以捕获所在函数的参数,所以在使用上更为灵活。
但 C++ 11 标准提供了标准库函数 bind
,解决了定义普通函数做谓词的情况下的参数个数限制问题。bind
定义在头文件 functional
中,作为一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象。
4.3.1 格式
auto newCallable = bind(callable, arg_list);
bind
函数接受一个可调用对象 Callable
和一个参数列表 arg_list
,返回一个新的可调用对象 newCallable
。
当调用 newCallable
时,newCallable
调用 callble
,并将参数列表 arg_list
中的参数传递给 callable
。
4.3.2 参数列表
arg_list
包括两部分:
newCallable
接受的参数。这些参数传递给newCallable
之后,又由newCallable
传递给callable
。在arg_list
中应以占位符_n
的形式出现,表示位于newCallable
参数列表中的第 n 个参数。- 其他参数。
_n
定义在命名空间 std::placeholders
中。
默认,非占位符参数被被拷贝到 bind
返回的可调用对象中。若要以引用方式传递,需使用头文件functional
中定义的标准库 ref
函数(返回引用)或 cref
函数(返回 const
引用)。