0

I'm trying to validate user input for integers only. My code works fine except when the user inputs 0. It doesn't consider it an integer, and it thinks the value is false. Here's a brief example of how I'm coding this project....

int main ()
{
    int num;
    cout  << "Please enter an integer: ";
    cin >> num;
    cout << endl;

     while (! num)
     {
          cout << "That is not an integer.\n";
          return;
     }
}

If the user inputs 0, I get sent into the while loop even though 0 is an integer.

2 Answers2

2

The expression !num is true if, and only if, num is 0. So your implementation is buggy.

The easiest thing to do is to use something like

if (!(std::cin >> num)){
    std::cout << "That is not an integer.\n";
}

If you want to validate the input yourself then consider reading in a std::string and checking if that can be converted to an integer. This is surprisingly non-trivial since the possible values an int can take are so platform dependent (some systems have a range as small as -32767 to +32767).

If you can, use boost::lexical_cast<int>(num); where I've upgraded num to a std::string type. (The header you need is <boost/lexical_cast.hpp>).

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • thanks! I must have been tired when writing this code, because I've definitely validated input this way in the past. Appreciate it! – tmkaplan94 Apr 11 '17 at 16:02
0

In c++ the built-in int type doesn't have any optional validity to it like it does in some other languages: "!num" just means "num==0" and not "num does not exist".

However C++17 has std::optional template, which can turn your vanilla int into exactly what you originally expected!

All you need is some simple template magic to make it work with istream:

template< class CharT, class Traits, class T >
basic_istream<CharT,Traits>& operator>>( basic_istream<CharT,Traits>&& st,  
                                         std::optional<T>& value )
{
    T res;
    st>>res;
    value = (st)?res:{};
    return st;
}

Come to think of it, STL should provide that overload from the box.

Now all you need is to replace your int num with std::optional<int> num and voila - your code works as intended.

Seriously though, just use Bathsheba's solution.

Ap31
  • 3,244
  • 1
  • 18
  • 25