2

I'm writing a custom >> operator, which reads an entire stream character by character and updates an object with each character, something like this:

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;
}

The idea is that the stream is read character by character, until reaching the end of the stream or until a character that MyClass doesn't like is encountered. When the latter happens, the operator will raise an error.

I'm intending for it to be used like this:

MyClass value;

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

The issue I'm encountering is that after the entire stream is read, istream::fail() returns true because the end of the stream was reached, which sets both eof and fail (as shown in other questions like this).

As a result std::cin >> value returns false even when the stream was processed successfully.

Now, the caller of the operator could potentially check if the eof bit is set, but I feel like this isn't idiomatic with other standard usage patterns of the >> operator - e.g. int x; if (cin >> x) { //do something }.

So my question is - Should I be calling istream::clear after successfully processing the stream?. Something like this:

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

That would clear the failbit and ensure that std::cin >> value would only return false if there's a legitimate stream error, or if an invalid character was encountered. However, I'm just not sure if this is idiomatic C++ or would cause other issues.

Thanks!

Code Slinger
  • 1,100
  • 1
  • 11
  • 16

1 Answers1

1

Should I be calling istream::clear after successfully processing the stream?

That would be fine since your stream succesfully read the entire input and that is what your user-defined operator>>() is supposed to do, so it should report success. I would change it to clear the mask except for the ios_base::eofbit as that is an extra bit of information that the user can use, and it won't affect the if statement:

if (!parsing_success)
  input.setstate(std::ios_base::failbit); 
else
  input.clear(std::ios_base::eofbit);
David G
  • 94,763
  • 41
  • 167
  • 253