Re: Can a cin >> be in a while()?
Hakusa@gmail.com wrote:
cout << "What is the base price of the product? ";
while( (cin >> basePrice) <= 0 )
{
cout << "The base price must be a positive number" << endl
<< "Please try again.";
}
The above code does not quite work right. It seems that the compiler
thinks of the "(cin >> basePrice)" as a boolean whether or not I have
the "( )".
The value of the expression (cin >> basePrice) is (a reference to) the
stream cin, which easily converts into a boolean value indicating
whether the stream is in a good state, i.e. (roughly) whether the last
operation on the stream succeeded.
Therefore,
while (cin >> basePrice, basePrice <= 0)
is the easiest fix that retains your original intention. Here, (cin >>
basePrice) is evaluated first, and (basePrice <= 0) is evaluated next
and becomes the value of the total expression.
In addition, good programs should always anticipate unexpected input
(such as non-digits) or unexpected end of input. Therefore, I propose
the following structure:
while (true) {
cout << "What is the base price of the product? ";
if (cin >> basePrice && basePrice > 0) {
cout << "A valid input: " << x << '\n';
// process basePrice
break;
}
else if (cin)
cout << "Please enter a positive number. ";
else if (!cin.eof()) {
cout << "Please enter a valid number. ";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
else {
cout << '\n';
cout << "End-of-input. Good-bye.\n";
break;
}
cout << "Try again.\n";
}
Alternatively, you may want to process basePrice *after* the while loop,
in which case you have to test again with "if (cin)" after the loop
because you reach the same point when an end-of-input is reached.
You may also want to make the structure into a separate function:
bool get_base_price(int& x)
{
while (true) {
cout << "What is the base price of the product? ";
if (cin >> x && x > 0) {
cout << "A valid input: " << x << '\n';
return true;
}
else if (cin)
cout << "Please enter a positive number. ";
else if (!cin.eof()) {
cout << "Please enter a valid number. ";
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
else {
cout << '\n';
cout << "End-of-input. Good-bye.\n";
return false;
}
cout << "Try again.\n";
}
// not reached
}
int main()
{
int basePrice;
if (get_base_price(basePrice)) {
// process basePrice
}
}
You may find some strange behaviour as you enter "-1 3" or "3x" in an
interactive environment, especially if you have successive questions.
It is less confusing when you ignore the rest of the line after reading
an item:
bool get_base_price(int& x)
{
while (true) {
cout << "What is the base price of the product? ";
if (cin >> x && x > 0) {
cout << "A valid input: " << x << '\n';
cin.ignore(numeric_limits<streamsize>::max(), '\n');
return true;
}
else if (cin)
cout << "Please enter a positive number. ";
else if (!cin.eof()) {
cout << "Please enter a valid number. ";
cin.clear();
}
else {
cout << '\n';
cout << "End-of-input. Good-bye.\n";
return false;
}
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Try again.\n";
}
// not reached
}
Or a more rigorous method is to validate the input is to get one lineful
of input as a string and scan it. Boost::lexical_cast can help you with
this:
#include <boost/lexical_cast.hpp>
bool get_base_price(int& x)
{
string line;
while (true) {
cout << "What is the base price of the product? ";
if (getline(cin, line))
try {
x = boost::lexical_cast<int>(line);
if (x > 0) {
cout << "A valid input: " << x << '\n';
return true;
}
else
cout << "Please enter a positive number. ";
}
catch (boost::bad_lexical_cast&) {
cout << "Please enter a valid number. ";
}
else {
cout << '\n';
cout << "End-of-input. Good-bye.\n";
return false;
}
cout << "Try again.\n";
}
// not reached
}
--
Seungbeom Kim
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]