Ответ 1
Во-первых, обратите внимание, что в этом случае нет реальной необходимости использовать std::copy
вообще. Вы можете просто инициализировать вектор непосредственно из итераторов:
vector<string> col((istream_iterator<string>(cin)),
istream_iterator<string>());
Это, вероятно, не делает код намного понятнее.
Насколько работает код, он, вероятно, немного более страшен, чем вы думаете. Istream_iterator выглядит смутно следующим образом:
template <class T>
class istream_iterator {
std::istream *is;
T data;
public:
istream_iterator(std::istream &is) : is(&is) { ++(*this); }
istream_iterator() : is(nullptr) {}
T operator++() { (*is) >> data; return *this; }
T operator++(int) { (*is) >> data; return *this; }
T const &operator*() { return data; }
bool operator !=(istream_iterator &end) { return (*is).good(); }
bool operator ==(istream_iterator &end) { return !(*is).good(); }
};
Очевидно, что более того я пропущу, но это больше всего нас беспокоит. Итак, что происходит, когда вы создаете итератор, он читает (или пытается) элемент из потока в переменную, которую я назвал data
. Когда вы разыскиваете итератор, он возвращает data
. Когда вы увеличиваете итератор, он читает (или пытается) следующий элемент из файла. Несмотря на то, что они написаны так, как будто они сравнивают один итератор с другим, operator==
и operator!=
действительно просто проверяют конец файла 1.
То, что затем используется std::copy
, которое (снова упрощенное) выглядит смутно следующим образом:
template <class InIt, class OutIt>
void std::copy(InIt b, InIt e, OutIt d) {
while (b != e) {
*d = *b;
++b;
++d;
}
}
Итак, это читает и элемент из входного итератора, записывает этот элемент в выходной итератор и повторяется до тех пор, пока итератор для текущей позиции не сравняется с итератором для конца ввода (что произойдет, когда вы достигнете конец файла). Обратите внимание, что в отличие от других итераторов единственной "конечной" позицией, которую вы можете использовать с итератором istream, является конец файла.
- Обратите внимание, что технически это не соответствует поведению. Я упростил сравнение, чтобы все было просто. Два итератора, построенные по умолчанию, должны сравнивать одинаковые значения, и если вы построите два итератора из одного потока, они должны сравниться как минимум, прежде чем вы что-нибудь прочитаете из потока. Это мало практических различий - единственное сравнение, которое вы видели в реальном использовании, - это определить, достигли ли вы конца файла.