32-算法的通用特征
16.6.2 算法的通用特征
正如您多次看到的,STL函数使用迭代器和迭代器区间。从函数原型可知有关迭代器的假设。例如,copy()函数的原型如下:
template<class InputIterator, class OutputIterator>
OutputIterator copy(InputIterator first, InputIterator last,
OutputIterator result);
因为标识符InputIterator和OutputIterator都是模板参数,所以它们就像T和U一样。然而,STL文档使用模板参数名称来表示参数模型的概念。因此上述声明告诉我们,区间参数必须是输入迭代器或更高级别的迭代器,而指示结果存储位置的迭代器必须是输出迭代器或更高级别的迭代器。
对算法进行分类的方式之一是按结果放置的位置进行分类。有些算法就地完成工作,有些则创建拷贝。例如,在sort()函数完成时,结果被存放在原始数据的位置上,因此,sort()是就地算法(in-place algorithm);而copy()函数将结果发送到另一个位置,所以它是复制算法(copying algorithm)。transform()函数可以以这两种方式完成工作。与copy()相似,它使用输出迭代器指示结果的存储位置;与copy()不同的是,transform()允许输出迭代器指向输入区间,因此它可以用计算结果覆盖原来的值。
有些算法有两个版本:就地版本和复制版本。STL的约定是,复制版本的名称将以_copy结尾。复制版本将接受一个额外的输出迭代器参数,该参数指定结果的放置位置。例如,函数replace()的原型如下:
template<class ForwardIterator, class T>
void replace(ForwardIterator first, ForwardIterator last,
const T& old_value, const T& new_value);
它将所有的old_value替换为new_value,这是就地发生的。由于这种算法同时读写容器元素,因此迭代器类型必须是ForwardIterator或更高级别的。复制版本的原型如下:
template<class InputIterator, class OutputIterator, class T>
OutputIterator replace_copy(InputIterator first, InputIterator last,
OutputIterator result,
const T& old_value, const T& new_value);
在这里,结果被复制到result指定的新位置,因此对于指定区间而言,只读输入迭代器足够了。
注意,replace_copy()的返回类型为OutputIterator。对于复制算法,统一的约定是:返回一个迭代器,该迭代器指向复制的最后一个值后面的一个位置。
另一个常见的变体是:有些函数有这样的版本,即根据将函数应用于容器元素得到的结果来执行操作。这些版本的名称通常以_if结尾。例如,如果将函数用于旧值时,返回的值为true,则replace_if()将把旧值替换为新的值。下面是该函数的原型:
template<class ForwardIterator, class Predicate class T>
void replace_if(ForwardIterator first, ForwardIterator last,
Predicate pred, const T& new_value);
如前所述,谓词是返回bool值的一元函数。还有一个replace_copy_if()版本,您不难知道其作用和原型。
与InputIterator一样,Predicate也是模板参数名称,可以为T或U。然而,STL选择用Predicate来提醒用户,实参应模拟Predicate概念。同样,STL使用诸如Generator和BinaryPredicate等术语来指示必须模拟其他函数对象概念的参数。请记住,虽然文档可指出迭代器或函数符需求,但编译器不会对此进行检查。如果您使用了错误的迭代器,则编译器试图实例化模板时,将显示大量的错误消息。