Необходимо очистить строку от cin , используя cin.ignore , в дополнение к очистке состояния потока (что делает cin.clear ).
У меня есть несколько служебных функций , чтобы упростить это (в частности, вас заинтересует clearline , который очищает состояние потока и текущую строку) и почти точный пример что вы хотите .
Ваш код, более или менее, используя мою clearline :
#include "clinput.hpp" // move my file to a location it can be used from
int main() {
using namespace std;
while (true) {
cout << "Enter a number (0 to exit): ";
int number;
if (cin >> number) {
cout << "Read " << number << '\n';
if (number == 0) {
break;
}
}
else {
if (cin.eof()) { // tested only *after* failed state
cerr << "Input failed due to EOF, exiting.\n";
return 1;
}
cerr << "Input failed, try again.\n";
clearline(cin); // "cin >> clearline" is identical
}
}
return 0;
}
Здесь все еще есть потенциальная проблема (исправлена в моем clinput_loop.cpp с blankline ), оставив вход в буфере, который позже испортит IO (см. «42 abc»). «в примере сессии). Извлечение приведенного выше кода в отдельную и самодостаточную функцию оставлено в качестве упражнения для читателя, но вот скелет:
template<class Type, class Ch, class ChTr>
Type read(std::basic_istream<Ch,ChTr>& stream, Ch const* prompt) {
Type value;
// *try input here*
if (could_not_get_input or more_of_line_left) {
throw std::runtime_error("...");
}
return value;
}
template<class Type, class Ch, class ChTr>
void read_into(
Type& value,
std::basic_istream<Ch,ChTr>& stream,
Ch const* prompt
) {
value = read<Type>(stream, prompt);
}
Пример использования:
int n;
try {
read_into(n, std::cin, "Enter a number: ");
}
catch (std::runtime_error& e) {
//...
raise;
}
cout << "Read " << n << '\n';
clearline функция, извлеченная для потомков, в случае, если вышеупомянутые ссылки когда-либо прерываются (и немного изменяются, чтобы сделать автономными):
#include <istream>
#include <limits>
template<class C, class T>
std::basic_istream<C,T>& clearline(std::basic_istream<C,T>& s) {
s.clear();
s.ignore(std::numeric_limits<std::streamsize>::max(), s.widen('\n'))
return s;
}
Материал шаблона немного сбивает с толку, если вы к нему не привыкли, но это не сложно:
- std :: istream - это typedef, равный
std::basic_istream<char, std::char_traits<char> >
- std :: wistream - это typedef, равный
std::basic_istream<wchar_t, std::char_traits<wchar_t> >
- расширение позволяет
'\n'
стать L'\n'
соответствующим образом
- этот код работает как для обычных char и wchar_t , так и для любых совместимых экземпляров basic_istream
- написано, что оно называется
clearline(stream)
или stream >> clearline
, сравните с другими манипуляторами, такими как std :: endl , std :: ws , или std :: boolalpha