算法要求的迭代器操作可以分为5个迭代器类别,每个算法都会对它的每个迭代器参数指明须提供哪类迭代器:
5类迭代器
一些操作所有迭代器都支持,另外一些只有特定类别的迭代器才支持:ostream_iterator
只支持递增、解引用和赋值,vector
、string
、deque
迭代器除了这些操作外,还支持递减、关系、算术运算。
输入迭代器
输入迭代器可以读取序列中的二元素,一个输入迭代器必须支持:
- 用于比较两个迭代器的相等和 不相等运算符(
==
、!=
)。 - 用于推进迭代器的前置和后置递增运算(
++
)。 - 用于读取元素的解引用运算符(
*
);解引用只会出现在赋值运算符的右侧。 - 箭头运算符(
->
),等价于*(it).member
,即,解引用迭代器,并提取对象 的成员。
输入迭代器只用于单遍扫描算法,算法 find
和 accumulate
要求输入迭代器;istream_iterator
是一种输入迭代器。
输出迭代器
输出迭代器可以看作输入迭代器上的补集,只写而不读元素,输出迭代器必须支持:
- 用于推进迭代器的前置和后置递增运算(
++
)。 - 解引用运算符(
*
),只出现在赋值运算符的左侧(向一个已经解引用的输出迭代器赋值,就是将值写入它所指向的元素)。
只能向一个输出迭代器赋值一次,类似输入迭代器,输出迭代器只能用于单遍扫描算法。用作目的位置的迭代器通常都是输出迭代器,例如:copy
函数的第三个参数就是输出迭代器,ostream_iterator
类型也是输出迭代器。
前向迭代器
前向迭代器可以读写元素,这类迭代器只能在序列中沿一个方向移动。前向迭代器支持所有输入和输出迭代器操作,而且可以多次读写同一个元素。
可以保存前向迭代器的状态,使用前向迭代器的算法可以对序列进行多遍扫描。算法 replace
要求前向迭代器,forward_list
上的迭代器是前向迭代器。
双向迭代器
双向迭代器可以正向/反向读写序列中的元素。除了支持所有前向迭代器的操作之外,双向迭代器还支持前置和后置的递减操作符(--
)。算法 reverse
要求双向迭代器,除了 forward_list
之外,其它标准库都提供符合双向迭代器要求的迭代器。
随机访问迭代器
随机访问迭代器提供在常量时间内访问序列中任意元素的能力。此类迭代器支持双向迭代器的所有功能:
- 用于比较两个迭代器相对位置的关系运算符(
<
、<=
、>
、>=
)。 - 迭代器和一个整数值的加减运算(
+
、+=
、-
、-=
),计算结果是迭代器在序列中前进或后退给定整数个元素后的位置。 - 用于两个迭代器上减法运算符(
-
),得到两个迭代器的距离。 - 下标运算符
(iter[n])
,与*(iter[n])
等价。
算法 sort
要求随机访问迭代器。array
、deque
、string
和 vector
的迭代器都是随机访问迭代器,用于访问内置数组元素的指针也是。
算法形参模式
大多数算法具有如下四种形式之一:
alg(beg, end, other args);
alg(beg, end,dest, other args);
alg(beg, end, beg2,other args);
alg(beg, end, beg2, end2, other args);
alg
表示算法的名字,beg
和 end
表示算法所操作的输入范围,几乎所有的算法都接受一个输入范围,是否有其他参数依赖于要执行的操作。dest
表示指定的目的位置,beg2
和 end2
表示第二个范围。
接受单个目标迭代器的算法
向输出迭代器写入数据的算法都假定目标空间足够容纳写入的数据。
如果 dest
是一个直接指向容器的迭代器,那么算法将输出数据写到容器中已存在的元素内,更常见的情况,dest
被绑定到一个插入迭代器或者是一个 ostream_iterator
。插入迭代器会将新元素添加到容器中,因而保证空间是足够的。ostream_iterator
会将数据写入到一个输出流,同样不管要写入多少个元素都没有问题。
接受第二个输入序列的算法
接受单独的 beg2
或是接受 beg2
和 end2
的算法用这些迭代器表示第二个输入范围。这些算法通常使用第二个范围中的元素与第一个输入范围结合来进行一些运算。
只接受单独的 beg2
的算法将 beg2
作为输入范围中的首元素,此范围的结束为止未指定,这些算法假定从 beg2
开始的范围与从 beg
和 end
所表示的范围至少一样大。
如果算法接受 beg2
和 end2
,这两个迭代器表示第二个范围,这类算法接受两个完整指定的范围:[beg,end)
范围和 [beg2,end2)
的第二个范围。
算法命名规范
一些算法使用重载形式传递一个谓词。
接受谓词参数来代替 <
或 =
运算符的算法,以及那些不接受额外参数的算法,通常都是重载的函数。函数的一个版本用元素类型的运算符来比较元素;另一个版本接受一个额外谓词参数,来代替 <
和 =
:
unique(behg,end); //使用 == 运算符比较元素
unique(behg,end,comp); //使用 comp 比较元素
两个调用都重新整理给定序列,将相邻的重复元素删除。
_if 版本的算法
接受一个元素值的算法通常有另一个不同名的(不是重载的)版本,该版本接受一个谓词代替元素值,接受谓词参数的算法都有附加的 _if
前缀:
find(beg,end,val); //查找输入范围中val第一次出现的位置
find_if(beg,end,pred); //查找第一个令pred位置的元素
这两个算法都在输入范围中查找特定元素第一次出现的位置。
算法 find
查找一个指定的值,算法 find_if
查找使得 pred
返回非零值的元素。
区分拷贝元素的版本和不拷贝的版本
默认情况下,重排元素的算法重排后的元素写回给定的输入序列中。这些算法还提供另一个版本,将元素写到一个指定的输出目的位置。写到额外目的空间的算法都在名字后面附加一个 _copy
:
reverse(beg,end); //反转输入范围中元素的顺序
reverse_copy(beg,end,dest); //将元素按逆序拷贝到dest
一些算法同时提供 _copy
和 _if
版本,这些版本接受一个目的位置迭代器和一个谓词:
//从v1中删除奇数元素
remove_if(v1.begin(),v1.end(),[](int i){return i % 2;});
//将偶元素从v1拷贝到v2;v1不变
remove_copy_if(v1.begin(),v1.end(),back_inserter(v2),[](int i){ i % 2;});