This actually takes a little more effort than you may expect. Мой совет должен был бы обернуть это в шаблоне вспомогательную функцию, которая принимает начальное и сообщение об ошибке, чтобы показать (хотя это приведет к дополнительной копии).
Учитывая, что примеры кода приветствуются, вот три общих способа сделать это. Прежде всего, мы могли бы читать, если у нас есть действительные целые числа: это более простой способ. (Обязательно включает в себя, как предполагается, присутствует.)
int main() {
std::vector<int> values;
int i;
while((std::cout << "Enter a number: ") && (std::cin >> i))
values.push_back(i);
// We've finished reading all values we could, let's work on them.
}
Этот путь короткий и простой, и позволит пользователю продолжить ввод «выход», или на самом деле что-нибудь еще, что это не число. Преимущество состоит в том, что вы можете перенаправить файл и не придется «выходить» в конце файла (EOF правильно завершит цикл). Однако это означает, что пользователь, допустивший ошибку, приводит к невозможности ввода каких-либо дополнительных данных.
В качестве альтернативы вы можете использовать что-то вроде этого, чтобы читать до конца потока, а затем вызывать исключение после этого. Это не особенно аккуратно: вы в конечном итоге бросаете исключение как часть обычной программной логики, которая обычно не одобряется. Вместо этого вы можете вернуть объект, построенный по умолчанию, или сбой сигнала с помощью других средств, но ни одна из них не станет особенно опрятной.
// You could pass in output streams for prompts and errors, too.
template<typename T>
T read(std::istream& is, std::string const& prompt, std::string const& error) {
T t;
while ((std::cout << prompt) && !(is >> t)) {
if (is.eof())
throw std::runtime_error("End of stream.");
std::cerr << error;
is.clear();
is.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
return t;
}
int main() {
std::vector<int> values;
int i = 1;
// This way, an input of 0 will terminate the loop. I've deviated from
// `exit' terminating the loop -- sentinel values like that aren't very
// flexible, so I wouldn't advise using it.
try {
while (i = read<int>(std::cin, "Please enter an integer: \n", "Error!\n"))
values.push_back(i);
}
catch (std::exception& e) {
// Have fun figuring out if this is end of input or something utterly unrelated.
}
}
Это позволит вам вводить ввод несколько раз, но это не совсем так, как аккуратно, и занимает намного больше кода.
И, наконец, баланс двух использует lexical_cast
для преобразования. Это часть усиления, но если вы не хотите использовать только вещи, предоставляемые стандартной библиотекой, она может быть реализована в виде
template<typename OUT, typename IN>
OUT lexical_cast(IN const& in) {
std::stringstream ss;
OUT o;
ss << in;
ss >> o;
// You may want more thorough error checking code
if (!ss)
throw std::runtime_error("Bad cast");
return o;
}
Это будет переводить с одного типа на другой на основе текстуально, а не бинарный, представление. Теперь вы можете сделать
int main() {
std::vector<int> values;
std::string input;
while ((std::cout << "Enter an integer: ") && (std::cin >> input)) {
if (input == "exit")
break;
try {
values.push_back(lexical_cast<int>(input));
}
catch (std::runtime_error& e) {
// Tell about the error, etc.
}
}
}
В некоторых случаях один из них явно лучше другого; это зависит от ожидаемого метода ввода (будет ли пользователь вводить вещи или файл, перенаправленный на стандартный ввод?) и насколько он устойчив к плохим вводам.
[Это как вы это делаете] (http://stackoverflow.com/questions/1283302/user-input-of-integers-error-handling). –