为啥 std::fill 使用 ForwardIterator,而不是 OutputIterator?

Posted

技术标签:

【中文标题】为啥 std::fill 使用 ForwardIterator,而不是 OutputIterator?【英文标题】:Why does std::fill use ForwardIterator, not OutputIterator?为什么 std::fill 使用 ForwardIterator,而不是 OutputIterator? 【发布时间】:2017-04-19 23:43:21 【问题描述】:

(此问题与Why does std::max_element require a ForwardIterator? 具有相同的“问题模板”,但答案必须不同,因为std::fill 不会将迭代器返回到输出序列中。)

std::fill 被定义为仅在输出范围由一对 ForwardIterators 给出时才起作用。然而,表面上相似的std::fill_n 可以很好地与 OutputIterator 配合使用。

算法肯定很简单

template<class OutIt, class T>
void fill(OutIt first, OutIt last, T value)

    while (first != last) 
        *first = value;
        ++first;
    

这个算法需要 ForwardIterator 怎么样?我错过了什么?

【问题讨论】:

【参考方案1】:

输出迭代器不可比较。没有为输出迭代器定义 ==!= 运算符。

你需要一个前向迭代器,因为它

满足输入迭代器的要求

支持EqualityComparable

使用输出迭代器,std::fill 无法将 firstlast 进行比较:

while (first != last) 

不支持,用于输出迭代器。

std::fill_n 避免了这种比较,它只是使用计数器写入迭代器,所以它只需要一个输出迭代器。

【讨论】:

哦,这是关于平等可比性的。恕我直言,不幸的是,当前的标准概念将“平等可比”的概念和“输入可迭代”的概念联系在一起——我认为有类似 class SentineledOstreamIterator 的东西是可比较的 o1 == o2 和可分配*o1 = v,但您仍然不被允许从中读取v = *o1。但是好吧,有了当前的概念层次结构,我明白为什么 OutputIterator 没有受到足够的约束。 @Quuxplusone 通用输出迭代器具有可比性是没有意义的;例如想象一下,如果输出迭代器正在输出到连接到终端的ofstream。比较其中两个是什么意思? 我想比较一般的 istream 迭代器也没有意义,尽管按顺序与单数迭代器(表示文件结束或错误)进行比较是有用的读取流的剩余部分;而对于输出,没有“写到文件结束”之类的东西 @M.M(第二条评论):完全正确! 通常输入和输出迭代器不可比较,但有时可以。例如,ostream_iterator::operator== 的语义可能类似于istream_iterator::operator==,即在底层流上返回(!x.ready() &amp;&amp; !y.ready()) || (&amp;x == &amp;y)。当然,这主要适用于想要“写入相同字节直到出现磁盘错误或文件系统已满”的程序,这可能是一种不常见的情况。 ;)【参考方案2】:

OutputIterator 没有“范围”的概念。因此,您必须提供重复计数。使用ForwardIterator,您可以处理一系列元素。

这些是语义不同的东西。 fill_n 用于从提供的迭代器开始添加一些元素。 fill 用于更改元素范围。

以插入器(例如back_inserter)为例。你可以插入比容器中更多的元素,所以last 甚至没有意义。

OutputIterator 为您提供了一个可以放入对象的地方。 ForwardIterator 对象必须存在。

来自cppreference:

带有输出迭代器的 operator* 唯一有效的用法是在赋值的左侧:operator* 可能返回一个代理对象,该对象定义了一个成员 operator=(可能是一个模板)

这意味着您基本上无法从中读取,这与ForwardIterator相反:

ForwardIterator 是一个可以从指向的元素中读取数据的迭代器。

【讨论】:

我认为您的编辑实际上将这个答案从“好”变为“更差”。 std::fill 不会尝试从其迭代器参数中读取;它确实仅在作业的左侧使用*x。因此,引入这个事实会激发我的问题,但它无助于回答它。 是否可以引用另一句话来对比 ForwardIterator 必须 可读以提供帮助?我知道fill 不读取元素,但这没关系。它旨在处理一系列元素。我不确定您是否不了解迭代器类型之间的区别,或者不了解使您提议的实现无法实现的技术性。我针对前者。后者在另一个答案中进行了解释。也许这个将来对其他人有用。

以上是关于为啥 std::fill 使用 ForwardIterator,而不是 OutputIterator?的主要内容,如果未能解决你的问题,请参考以下文章

使用 std::fill 填充多维数组的安全方法是啥?

在 2D int 向量上使用 std::fill

使用带有std :: fill等算法的emplace

C++ std :: fill()函数

为啥或为啥不在 C++ 中使用 memset? [关闭]

是否有类似 STL 的函数来用索引的某些函数填充数组?