Идиоматический цикл для чтения из istream
while (thestream >> value)
{
// do something with value
}
Теперь этот цикл имеет одну проблему: он не будет отличать, если цикл завершен из-за конца файла или из-за ошибки. Например, возьмите следующую тестовую программу:
#include <iostream>
#include <sstream>
void readbools(std::istream& is)
{
bool b;
while (is >> b)
{
std::cout << (b ? "T" : "F");
}
std::cout << " - " << is.good() << is.eof() << is.fail() << is.bad() << "\n";
}
void testread(std::string s)
{
std::istringstream is(s);
is >> std::boolalpha;
readbools(is);
}
int main()
{
testread("true false");
testread("true false tr");
}
Первый вызов testread
содержит два допустимых типа bool и, следовательно, не является ошибкой. Второй вызов заканчивается третьим, неполным bool и, следовательно, является ошибкой. Тем не менее, поведение обоих одинаково. В первом случае чтение логического значения не выполняется, потому что его нет, а во втором случае он терпит неудачу, потому что он неполный, и в обоих случаях удаляется EOF. Действительно, вышеприведенная программа выводит дважды ту же строку:
TF - 0110
TF - 0110
Чтобы решить эту проблему, я подумал о следующем решении:
while (thestream >> std::ws && !thestream.eof() && thestream >> value)
{
// do something with value
}
Идея состоит в том, чтобы обнаружить обычный EOF, прежде чем пытаться извлечь значение. Поскольку в конце файла может быть пробел (что не было бы ошибкой, но причиной того, что последний элемент не попал в EOF), я сначала отбрасываю любые пробелы (которые не могут потерпеть неудачу), а затем проверяет EOF. Только если я не в конце файла, я пытаюсь прочитать значение.
В моей примерной программе это действительно работает, и я получаю
TF - 0100
TF - 0110
Итак, в первом случае (правильный ввод), fail()
возвращает false.
Теперь мой вопрос: Является ли это решение гарантированным, или я просто (не) повезло, что это дало желаемый результат? Также: есть ли более простое (или, если мое решение неправильно, правильный) способ получить желаемый результат?