Я обнаружил разницу в поведении разных компиляторов. Предположим, что следующий код:
#include <sstream>
#include <iostream>
using namespace std;
int main() {
istringstream ss("100");
int val;
ss >> val;
cout << "fail: " << ss.fail() << " eof: " << ss.eof() << endl;
ss >> std::ws;
cout << "fail: " << ss.fail() << " eof: " << ss.eof() << endl;
}
Результат, сгенерированный VS2019 и Clang 10 с libc ++:
fail: 0 eof: 1
fail: 1 eof: 1
В то время как VS2015 и G CC 10.2 с libstdc ++ генерирует:
fail: 0 eof: 1
fail: 0 eof: 1
Итак, вопрос в том, какая реализация правильная? Следует ли std::ws
устанавливать failbit, когда eofbit уже установлен?
Я поискал std::ws
в стандарте, в котором говорится:
30.7.4.4 Стандартные манипуляторы basic_istream [istream .manip]
шаблон basic_istream & ws (basic_istream & is);
Эффекты: Ведет себя как неформатированная функция ввода (30.7.4.3), за исключением того, что не подсчитывает количество извлеченных символов и не влияет на значение, возвращаемое последующими вызовами is.gcount ( ). После создания сторожевой объект извлекает символы до тех пор, пока следующий доступный символ c является пробелом или пока в последовательности не останется символов. Пробельные символы различаются по тому же критерию, что и sentry :: sentry (30.7.4.1.3). Если ws перестает извлекать символы, потому что их больше нет, он устанавливает eofbit, но не failbit.
Итак, в конце явно указано, что он устанавливает eofbit, но не failbit, когда символы недоступны. Но тогда он также ведет себя как неформатированная функция ввода, которая создает объект sentry
. Конструктор sentry
затем вызовет is.setstate(failbit)
, если is.good()
ложно. Так что в каком-то смысле обе реализации не совсем ошибочны. Может ли кто-нибудь, кто лучше разбирается в стандартном языке, пояснить, какой вариант правилен и где мне следует сообщить об ошибке?