失敗した場合cin >> num
、無効な入力をストリームから削除する必要があります。これを達成するためignore
に代わりに使用することをお勧めします。sync
その理由はsync
、標準ライブラリのすべての実装で残りの入力を削除することが保証されていないためです。
#include <iostream>
#include <limits>
int main()
{
int num;
while (cout << "Enter a number" && !(cin >> num))
{
cin.clear(); // clear the error
// Remove input up to a new line
cin.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
cout << "Invalid input; please re-enter.\n";
}
}
上記の使用例はstd::numeric_limits<std::streamsize>::max()
、入力バッファーが保持できる最大文字数を取得するために使用されます。これによりignore()
、新しい行まで可能な限り多くの文字を削除できます。これは慣用的な C++ であり、現在抱えている問題を隠すだけのマジック ナンバーを使用するよりも好まれます。
これはうまく機能しますが、入力の数字の後に余分な文字が含まれている状況を処理しません。このような状況に対処するには、追加の検証を処理するためにループを少し変更する必要があります。1 つのオプションは、 から行全体を読み取り、cin
それを に配置し、std::stringstream
そこから数値を読み取り、追加の検証を行うことです。ただし、考慮する必要がある特殊なケースが 1 つあります。数字の後の文字が空白のみである行です。幸いなことに、標準ライブラリにはstd::skipws
、状況を簡単に処理できるストリーム修飾子が用意されています。以下の例は、あまり手間をかけずにこれを行う方法を示しています
#include <iostream>
#include <sstream>
int main()
{
int num;
for(;;)
{
std::cout << "Enter a number: " << std::flush;
std::string line;
std::getline(std::cin, line); // Read a line from console
std::stringstream text(line); // store in a string stream
char ch = 0;
if(!(text >> num).fail() && (text >> std::skipws >> ch).fail())
{
break;
}
std::cout << "Invalid input; please re-enter.\n";
}
return 0;
}
この式(text >> std::skipws >> ch).fail()
は、数字の後に表示されるすべての空白をスキップしてから、1 文字を読み取ろうとします。使用可能な文字がない場合、読み取りは失敗し、ユーザーが数字のみを入力したことを示します。これを実行しようとするとcin
、入力が有効であっても、ユーザーがさらにテキストを入力するのを待つことになります。