C ++ является статически типизированным языком.Тип переменной будет фиксированным во время компиляции и не может быть изменен во время выполнения.Однако то, что вводят пользователи, будет известно только во время выполнения и не может быть известно во время компиляции.Поэтому ваш вопрос не имеет смысла.
Когда вы ожидаете целое число от пользователя, тогда лучшим способом будет попытка прочитать целое число и проверить, успешно ли это:
int i;
std::cin >> i;
if(!std::cin)
throw "Stupid user blew it!"; // or some real error handling
Однако, ловушкаэто означает, что после сбоя операции ввода поток ввода переходит в плохое состояние, и данные, которые не могут быть прочитаны, остаются во входном буфере.Если вы хотите обработать это изящно, придется очистить флаги состояния ошибки потока и заставить его игнорировать все, что находится во входном буфере.
Так что иногда может проще сначала прочитать строку
std::string input;
std::cin >> input; // either read up to any whitespace, or
std::getline(std::cin, input); // newline, or
std::getline(std::cin, input, '\t'); // tab, or whatever you want
, потому что это всегда удается, а затем попытаться преобразовать ее в любые данные, которые вам нужны.Способ сделать это через строковые потоки:
std::istringstream iss(input);
int i;
iss >> i;
Теперь вы можете проверить состояние потока строки
if(!iss)
, и если преобразование не удалось, std::cin
все еще будет использоваться иошибочный ввод прочитан из его буфера.
Однако есть еще одна загвоздка: если пользователь вводит «42 тысячи», то это не поймает ошибку.Остальные символы будут находиться во входном буфере потоков строк и будут игнорироваться.Поэтому для такого преобразования обычно требуется проверить, полностью ли прочитан буфер потока строки: чтение достигло EOF.Вы можете проверить это, вызвав iss.eof()
.Однако, если вы прочитаете целую строку , в конце может быть дополнительный пробел, который не должен приводить к сбою преобразования, поэтому вам нужно прочитать лишний пробел, прежде чем проверять EOF: iss >> std::ws
.(std::ws
- это потоковый манипулятор, который "съедает" последовательные пробелы.)
к настоящему времени преобразование будет выглядеть так:
std::istringstream iss(input);
int i;
iss >> i >> std::ws; // you can chain input
if(!iss.eof())
throw invalid_input(input);
Конечно, это довольно сложно для одноразового использования.обращение и я бы точно не поклялся жизнью своих детей, что не осталось хорошего улучшения, о котором я еще не думал.Поэтому вы, по крайней мере, захотите обернуть это в функцию и поместить ее в свой набор инструментов для ее повторного использования (и исправления, если найдете ошибку):
bool convert_to_int(const std::string& str, int& result)
{
std::istringstream iss(input);
iss >> result >> std::ws;
return iss.eof();
}
Или, универсальный для любого типа:
template< typename T >
bool convert_from_string(const std::string& str, T& result
{
std::istringstream iss(input);
iss >> result >> std::ws;
return iss.eof();
}
Еще лучше было бы использовать для этого готовое готовое решение. Boost имеет именно такую вещь со своим lexical_cast
.
Вот скелетный алгоритм для всей процедуры ввода:
int i;
do {
read string input
convert to int i
while(!conversion succeeded);
С помощью битов, приведенных выше, вы сможете заполнить недостающие части.