The problem here is that the character sequence 2.5
clearly starts with a valid integer, i.e., with 2
. This is what the stream successfully reads. Thus, after reading 2
there is no reason for the stream to fail.
One way to you could deal with the situation is to read an integer and if this is successful inspect the character which caused the read operation to stop: if this character is a suitable separator, e.g., a space, the end of the file, etc., you consider the input to be successful:
bool is_integer_separator(int value) {
return value == std::char_traits<char>::eof() // at the end of the file
|| value == ',' // accept comma as separator
|| std::isspace(static_cast<unsigned char>(value)); // ... and space
}
// ...
int value;
if (std::cin >> value && is_integer_separator(std::cin.peek())) {
...
}
else {
std::cout << "Not an integer\n";
}
In general, reading an integer and stopping when a character is encountered which doesn't suit an integer is the desired definition of success. If you need a most customized definition, you can build it from this functionality combined with seeing what is coming next in the stream. The std::istream::peek()
member looks at the next character without extracting it. It return std::char_traits<char>::eof()
if there is a failure, e.g., the stream was in failure-mode (i.e., it has std::ios_base::failbit
or std::ios_base::badbit
set) or the end of the file was reached. Since the stream was OK right before this operation the only possible failure is having reached the end of the file. You can then consider whatever character is encountered and determine if you want to accept it. The example considers spaces and ','
as viable separators. Note, that the next character isn't extracted, yet, i.e., you might want to get rid of it, using, e.g., std::cin.ignore()
.