Следует ли вызывать istream :: clear () в моем пользовательском операторе >>? - PullRequest
2 голосов
/ 18 июня 2020

Я пишу собственный оператор >>, который считывает весь символ потока за символом и обновляет объект каждым символом, примерно так:

class MyClass 
{
    public:
        bool Process(char c);
}

std::istream& operator>>(std::istream& input, MyClass& value)
{
    if (input)
    {
        char c;
        bool parsing_success = true;

        while (parsing_success && input >> c)
        {
            parsing_success = value.Process(c)
        }

        if (!parsing_success)
            input.setstate(std::ios_base::failbit);            
    }

    return input;
}

Идея в том, что поток читать символ за символом, пока не будет достигнут конец потока или пока не встретится символ, который MyClass не нравится. В последнем случае оператор выдаст ошибку.

Я собираюсь использовать его следующим образом:

MyClass value;

if (std::cin >> value)
{
    //do something with value
}
else
{
    //handle error
}

Проблема, с которой я сталкиваюсь, заключается в том, что после всего поток читается, istream::fail() возвращает true, потому что был достигнут конец потока, что устанавливает как eof, так и fail (как показано в других вопросах, таких как this ).

В результате std::cin >> value возвращает false, даже если поток был успешно обработан.

Теперь вызывающий оператор потенциально может проверить, установлен ли бит eof, но я чувствую как это не идиоматия c с другими стандартными шаблонами использования оператора >> - например, int x; if (cin >> x) { //do something }.

Итак, мой вопрос - Должен ли я вызывать istream :: clear после успешного обработка потока? . Что-то вроде этого:

if (!parsing_success)
    input.setstate(std::ios_base::failbit); 
else
    input.clear();

Это очистит бит отказа и гарантирует, что std::cin >> value вернет false только в случае допустимой ошибки потока или при обнаружении недопустимого символа. Однако я просто не уверен, что это идиоматия c C ++ или вызовет другие проблемы.

Спасибо!

1 Ответ

1 голос
/ 18 июня 2020

Следует ли мне вызывать istream::clear после успешной обработки потока?

Это было бы хорошо, поскольку ваш поток успешно прочитал весь ввод, и это то, что определено вашим пользователем operator>>() должен делать, поэтому он должен сообщать об успехе. Я бы изменил его, чтобы очистить маску, за исключением ios_base::eofbit, поскольку это дополнительный бит информации, который может использовать пользователь, и он не повлияет на оператор if:

if (!parsing_success)
  input.setstate(std::ios_base::failbit); 
else
  input.clear(std::ios_base::eofbit);
...