Если мы, например, попробуем считать целое число, но во входных данных следующим является токен "foobar"
int
выполнить нельзя и объект потока входит в cin.clear()
с целью вернуть cin
в рабочее состояние. Но после этого его внутренний курсор все еще находится в той позиции, где лежат данные, которые мы ввели вместо чисел. Чтобы отбросить старые входные данные и очистить канал для ввода имен, мы применили очень длинное выражение, cin.ignore(std::numeric_limits::max(), '\n');
. Необходимо удалять все, что находилось в буфере, поскольку он нужен абсолютно пустым, когда мы запросим у пользователя список имен.Следующий цикл также может показаться странным на первый взгляд:
for (string s; getline(cin >> ws, s, ',');) { ... }
В условной части цикла мы использовали функцию getline
,
), чтобы все имена из списка наподобие "john, carl, frank"
считывались отдельно.Пока все идет по плану. Но что означает предоставление функции cin >> ws
cin
отбросить все пробелы, которые стоят перед следующим символом, не являющимся пробелом, а также в конце строки. Если бы мы не применили ws
, то из строки "john, carl, frank"
получили бы подстроки "john"
, " carl"
и " frank"
. Заметили лишние пробелы для имен carl
и frank
? Они пропадают, поскольку мы использовали ws
. Подсчитываем все слова в файле
Предположим, мы считали текстовый файл и хотим определить количество слов в тексте. Словом, мы называем диапазон символов, расположенный между пробелами. Как же решить эту задачу?
Например, можно подсчитать количество пробелов, поскольку между словами должны быть пробелы. В предложении "John has a funny little dog."
Но как быть с предложением, содержащим разные виды пробелов, например: "John has \t a\nfunny little dog."
Помимо нахождения элегантного решения этой проблемы, мы позволим пользователю решать, для каких именно входных данных считать количество слов — для данных из стандартного потока ввода или из текстового файла.
Как это делается
В этом примере мы напишем короткую функцию, которая считает количество слов из входного буфера и позволяет пользователю выбирать, откуда именно во входном буфере появятся данные.
1. Включим все необходимые заголовочные файлы и объявим об использовании пространства имен std
#include
#include
#include
#include
#include
using namespace std;
2. Функция wordcount
cin
. Она создает итератор std::input_iterator
, который токенизирует строки потока, а затем передает их в std::distance
. Параметр distance
принимает в качестве аргументов два итератора и пытается определить, сколько именно операций инкремента нужно выполнить, чтобы переместиться с одной позиции итератора в другую. Для operator-
). Такие итераторы можно вычитать друг из друга, как и другие указатели. Итератор istream_iterator
, однако, является однонаправленным, и его нужно сдвигать вперед до тех пор, пока он не станет равен итератору end
. В конечном счете количество шагов будет равно количеству слов.template
size_t wordcount(T &is)
{
return distance(istream_iterator
}
3. В нашей функции main
std::cin
или из файла: