The problem:
The last extraction you performed before the call to std::getline()
was:
while (!(cin >> n2)) { cout << "Please enter a number for the final state" << endl; cin.clear(); cin.ignore(numeric_limits<streamsize>::max(), '\n'); }
Which is perfectly fine. The only problem is that, given a valid extraction, the newline character '\n'
will be left in the stream. By default, the unformatted input function std::getline()
delimits input upon the acquisition of a newline character. If the residual newline is still left in the stream, the input cannot be performed.
Note that technically std::getline()
discards the character but ceases extraction once it is found.
The solution:
The solution I suggested in the comments section of your question was to execute the following lines of code above your unformatted extraction:
std::cin.clear(); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
What this does in order is clear the underlying stream state (a bitmask that represents errors during I/O) and ignore the maximum amount of characters until the next newline character is found (it also consumes the newline).
Why did I suggest this?
If the stream state has a bit turned on (either failbit
, eofbit
, or badbit
) the stream won't be able to perform I/O (this also includes ignoring characters). The ignore()
call is used to discard any residual input until we reach the end of the line, so we have a fresh new line to restart input.
However, since you updated your post showing me the full code, I now realize that those two calls are not needed as you already took care of invalid input in the first code example I showed you. Moreover, since you made sure the most recent extraction succeeded, there's no need to reset the stream state.
Instead, what I propose is to use the manipulator std::ws
which will discard all whitespace characters (newline is also considered whitespace) until a non-whitespace character is found. It is a much more idiomatic approach to discarding newlines:
std::getline(std::cin >> std::ws, units); // ^^^^^^^^^^^^^^^^^^^
This should be equivalent to the ignore()
call because all that's left in the stream is a newline.
Improvements:
Here are a few:
The first is to always check if your input succeeded:
if (std::getline(std::cin >> std::ws, units)) { // }
If
units
will always be one character, then just use a character:char units; if (std::cin >> units) { if (units == 'e' || ... ) }