Search code examples
c++operator-overloadingifstreamistream

Custom istream operator always returning false


I have this issue where my custom overloaded >> operator always evaluates as 'false' when I check for success. I think it may have to do with the fact that my istream is infact a redirected ifstream (meaning I passed an ifsteam to the isteam), though I'm unsure how to solve it.

Here's the code snippet, simplified as much as it can be:

#include <istream>
#include <string>
#include <fstream>
#include <iostream>

class SomeClass {
public:
    SomeClass() = default;

    friend std::istream& operator>>(std::istream& is, SomeClass& random);

private:
    std::string my_str;
};

std::istream& operator>>(std::istream& is, SomeClass& random) {

    while(std::getline(is, random.my_str));

    if (random.my_str != "Hello World") {
        is.setstate(std::ios::failbit);
        return is;
    }

    is.setstate(std::ios::goodbit); //I didn't have this here before, put it in as a test
    return is;

}

bool io_parser(std::istream& input_stream) {

    SomeClass random;

    if (!(input_stream >> random))
        return false;

    return true;

}

int main(int argc, char* argv[]) {

    std::cout << argc << std::endl;
    std::istream* input_stream;

    std::ifstream input_file(argv[1]);

    if (!input_file.is_open()) {
        std::cout << "File failed to open." << std::endl;
        return EXIT_FAILURE;
    }

    input_stream = &input_file;
    std::cout << io_parser(*input_stream) << std::endl;

    return EXIT_SUCCESS;

}

Sample input:

Hello World
Hello World
Hello World

No matter what, it won't work as long as the std::getline() is in a while(). If it's alone, it works.


Solution

  • You have a couple of issues.

    while(std::getline(is, random.my_str));
    

    will always keep reading and discarding lines until it encounters an error. This may be what you intended but seems odd? After this loop the stream will be in a failed state (normally with eof set).

    is.setstate(std::ios::failbit);
    

    correctly sets the fail bit. However

    is.setstate(std::ios::goodbit);
    

    is not the way to return the stream to a good state. setstate adds the flag you specify to the current stream state, as goodbit is actually 0, setstate(std::ios::goodbit) has no effect on the stream state. To set the stream state you need to call clear:

    is.clear(std::ios::goodbit);
    

    or for setting std::ios::goodbit you can just call with no arguments:

    is.clear();