I have the following code:
#include <algorithm>
#include <ios>
#include <iostream>
#include <string>
#include <vector>
std::vector<int> read_ints(std::istream& is)
{
std::vector<int> res;
std::cout << "Please input a list of integers ('quit' to finish):" << std::endl;
for (int i; is >> i; )
{
res.push_back(i);
}
if (is.eof()) // fine: end of file
{
std::cout << "EOF reached" << std::endl;
return res;
}
std::cout << (is.bad() ? "1) BAD\n" : "");
std::cout << (is.fail() ? "1) FAIL\n" : "");
if (is.fail()) // we failed to read an int: was it the 'quit' string?
{
is.clear(); // reset the state to good
std::cout << (is.bad() ? "2) BAD\n" : "");
std::cout << (is.fail() ? "2) FAIL\n" : "");
is.unget(); // put the non-digit back into the stream
std::cout << (is.bad() ? "3) BAD\n" : "");
std::cout << (is.fail() ? "3) FAIL\n" : "");
std::string s;
if (is >> s && s == "quit")
{
std::cout << "Exiting correctly" << std::endl;
return res;
}
std::cout << "Exiting with an error. User typed: " << s << std::endl;
is.setstate(std::ios_base::failbit); // add fail() to stream's state
}
return res;
}
int main()
{
// Read ints
auto v = read_ints(std::cin);
bool first = true;
std::for_each(v.begin(), v.end(),
[&first](int n) { std::cout << (first ? "" : " ") << n; first = false; });
std::cout << std::endl;
}
If I input one or more numbers followed by a word (e.g. 1hola
, 1 2 3 quit
), the is.unget()
doesn't set neither the fail bit nor the bad bit, and I get the expected output messages (e.g. Exiting with an error. User typed: hola
, Exiting correctly
).
But if I just input a word (e.g. hola
or quit
), the is.unget()
sets fail bit and bad bit and I cannot recover the last input, getting the message Exiting with an error. User typed:
.
Why can't we put whatever we read from the stream back into it for the latter case?
Your mistake seems to be thinking that when reading an integer and a non-digit is found that character is consumed. It isn't. Just remove the call to std::unget
.