一、概述
1、大多数算法都定义在头文件algorithm中;头文件numeric中定义了一组数值泛型算法
2、一般情况下,这些算法并不直接操作容器,而是遍历两个迭代器指定的一个元素范围
- 算法永远不会改变底层容器的大小,想要改变必须使用容器自带的操作
二、初识泛型算法
1、理解算法最基本的方法是了解他们是否读取元素、改变元素或是重排元素顺序
2、那些只接受一个单一迭代器来作为第二个序列的算法,都假定第二个序列至少与第一个序列一样长
三、定制操作
1、一元谓词:只接受单一参数;二元谓词:有两个参数
2、lambda表达式:一个可调用的代码单元:一个未命名的内联函数
- [capture list](parameter list) –> return type { function body }
- capture list:捕获列表:lambda所在函数中定义的局部变量的列表(通常为空)
- lambda必须使用尾置返回来指定返回类型:如果只有包含return意外的语句,默认返回void,所以就必须自己指定返回类型;
- 可以忽略参数列表和返回类型,但是必须包含捕获列表和函数体
- auto f = [] {return 42;};
- lambda不能有默认参数
- 一个lambda只有在其捕获列表中捕获一个它所在函数中的局部非static变量,才能在函数体中使用该变量;可以直接使用局部static变量和它所在函数之外声明的名字
- 变量的捕获方式也可以是值或引用;如果是引用捕获一个变量时,必须保证在lambda执行时变量存在
- 一般,我们应该减少捕获的数据量,来避免潜在的捕获导致的问题;而且,可能的话,应该避免捕获指针和引用
- 可以通过编译器根据lambda体中的代码来推断捕获的变量:隐式捕获
- &:采用捕获引用方式;
- =:采用值捕获方式;
- 当混合使用隐式和显式捕获时,捕获列表中的第一个元素必须是一个&或=;且显式捕获的变量必须使用与隐式捕获不同的方式
3、参数绑定:可以把一个接受很多参数的函数绑定一个可调用的对象,来满足算法对一元谓词的要求
- auto newCallable = bind(callable, arg_list);
for_each(words.begin(), words.end(), bind(print, ref(os), _1, ' '));
- _1为print的第一个参数,其他为默认参数
4、lambda和函数:
- 如果只有在一个两个地方使用的简单操作,lambda表达式最有效,如果需要多个地方使用相同的操作,通常应该定义一个函数
- 如果lambda的捕获列表为空,通常可以用函数来代替他
- 如果一个操作需要很多语句才能完成,通常使用函数
四、迭代器
1、插入迭代器:实现向给定容器添加元素
- back_inserter:创建一个使用push_back的迭代器
- front_insert:创建一个使用push_front的迭代器
- inserter:创建一个使用insert的迭代器
- inserter(c, iter)
- c为要插入的容器,iter为给定的迭代器:元素被插入到给定迭代器锁表示的元素之前
- inserter(c, iter)
2、流迭代器:绑定到输入或输出流上,用来遍历关联的IO流
3、反向迭代器:通过调用rbegin、rend、 crbegin、和cend成员函数来获得反向迭代器
- 只能从既支持++也支持--的迭代器来定义反向迭代器
- 不可能从forward_list或流迭代器创建反向迭代器
4、移动迭代器:不拷贝而是移动它们,13.6.2介绍