c++validationcin

cin type check failed for '+'/'-'


The scenario is: input integers and characters alternatively and read them into variables of the right type. I took the straightforward approach: read anyways as if they were all integers; when failed, reset cin flags and read as characters.

int a;
char c;
while (true) {
    cin >> a;
    if (cin.fail()) {
        if (cin.eof()) {
            cout << "eof" << endl;
            break;
        }
        cin.clear();
        cin >> c;
        cout << "fail: " << c << ": " << int(c) << endl;
    }
    else {
        cout << "success: " << a << endl;
    }
}

It works just fine except for the very two characters: +, -. For instance, when you input 2 4 + 5 *, the output would be:

success: 2
success: 4
fail: 5: 53
fail: *: 42
eof

For *, it works; but for +, it seems that + is lost and 5 is read instead. I did some tests myself (e.g. using cin.get() instead) and found that: after cin >> a failed when encoutering +, + is consumed and the stream position points at the space between + and 5.

What makes + and - special? After some researches, I think the reason is possibly that: when cin expects an integer, the + or - it encounters is accepted as a possible prefix of integers like +5, -3, etc. This leads to the fact that + is consumed, rather than remains in the input stream like other characters.

How do you interpret the problem? How to fix the code to make it function properly?

PS: I know that one alternative solution is to read them all as strings and then do further parsing. I'm just curious whether it's possible to modify it based on the original approach. This way I could be more clear about the machanisms behind cin.


I think this post can be closed now. Thanks for all the comments and answers. The opinions and advice you shared are greatly appreciated, which I learned a lot from.

As I've said, it's not about practical use and I'm not looking for a well-rounded solution in the first place. In practice I will surely take the string-based approaches as suggested by you. It's just a small problem I ran into, after which I decided to take a short digression and play around the issue a little bit.

As for the question I raised, i.e. fixing the code, I've learned some from the answers below and official Docs. Using functions like cin.putback() cin.peek() cin.tellg() cin.seekg() will help tackle the problem.


Solution

  • The comments to your question show that there are much more to think than the mere "+/-" issue.

    Yet as to tackle this issue, your analysis is correct in the sense that these characters can be interpreted as the beginning of an int and got consumed.

    A workaround for this issue only is to parse char by char and not by int and to handle specifically + and -:

    int a;
    char c;
    while (true) {
        char ch;
        if (std::cin >> ch) {
            if (ch == '+' || ch == '-') {
                // Consume the special character and continue
                std::cout << "special char: " << ch << '\n';
                continue;
            } else {
                // Try to read the character as an integer
                std::cin.putback(ch);
                if (std::cin >> a) {
                    std::cout << "success: " << a << '\n';
                } else {
                    std::cin.clear();
                    std::cin >> c;
                    std::cout << "fail: " << c << ": " << int(c) << '\n';
                }
            }
        } else if (std::cin.eof()) {
            std::cout << "eof" << '\n';
            break;
        } else {
            std::cin.clear();
            std::cin >> c;
            std::cout << "fail: " << c << ": " << int(c) << '\n';
        }
    }
    

    Take notice of the usage of putback that allows to "unconsume" +or - and then try to read an int.

    input:

    24+5

    output

    success: 24
    special char: +
    success: 5

    But remember: it's only a quick workaround for this single issue but parsing a possibly ill -formed expression will raise many other issue that won't be solved by merely elaborating upon this fix.