为啥 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
无法将 first
与 last
进行比较:
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() && !y.ready()) || (&x == &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?的主要内容,如果未能解决你的问题,请参考以下文章