Из стандарта [24.5.1] / 1:
[...] Конструктор без аргументов
istream_iterator () всегда создает
конец входного итератора потока
объект, который является единственным законным
итератор, который будет использоваться для конца
состояние. [...] Главная особенность итераторов istream заключается в том, что операторы ++ не сохраняют равенство, то есть i == j вовсе не гарантирует, что ++ i == ++ j. Каждый раз, когда используется ++, читается новое значение.
[24.5.1] / 3
Два итератора конца потока
всегда равны Конец потока
итератор не равен
итератор без конца потока. Два
итераторы без конца потока равны
когда они построены из
тот же поток
В первом абзаце говорится, что вы не можете использовать любые итераторы конца потока в качестве конечных условий, поэтому ваше первое использование правильное и ожидаемое. Третий абзац в этой главе гласит, что любые два итератора, не относящиеся к концу потока, в один и тот же поток гарантированно всегда будут равны. То есть второе использование является правильным с точки зрения языка и обеспечит результаты, которые вы получаете.
Последняя часть параграфа 1, где говорится, что i == j
не подразумевает ++i == ++j
, имеет дело с частным случаем одного последнего элемента, присутствующего в потоке. После приращения первого из итераторов (i
или j
) этот итератор использует данные. Продвижение другого итератора дойдет до конца потока, и поэтому два итератора будут различаться. Во всех остальных случаях (в потоке осталось более одного элемента данных), ++i == ++j
.
Также обратите внимание, что предложение ++i == ++j
выполняет две операции мутирования для одного и того же элемента (потока), и, следовательно, это не тот, который из двух итераторов получает первый / второй элемент данных в потоке.