Checking the type of a variable

Started by
3 comments, last by mreit 15 years, 10 months ago
I'm very new to C++ and I am writing a console application just to get the hang of it. I was wondering, is there a way to check what the user puts into the console for the actual type of variable? Example: If a user puts a char where they're supposed to put an int. This way if they enter the wrong type, then I can just make it so the program asks the user again instead of acting funny.
Advertisement
When using a formatted extraction operator on a C++ input stream, if the contents of the stream cannot be converted to the desired type, the stream object will have its state set to a failure state. You can check if the extraction failed by examining the state of the stream. If the extraction failed, then to retry input, you would need to reset the state of the stream and then flush any unread characters from the stream. For example:

  int value;  while (!(std::cin >> value)) {    std::cin.clear();    std::cin.ignore(std::cin.rdbuf()->in_avail() + 1);  }  std::cout << value << std::endl;

Alternately, you can try using getline() to read lines at a time and then use a std::stringstream or boost::lexical_cast to convert the line into the desired type.
The C++ streams handle this for you, if you try to store invalid input in a type, the stream will enter a "failed" state, and will refuse to read any more input until you rectify this. We can test whether a stream is in a failed state by using the name of the stream in an if condition:
std::cin >> someVariable;if( std::cin ){   // std::cin is fine, read succeeded}else{   // something went wrong.   // could be end of file, or an error reading}


One handy thing about stream operations is that they "return" the stream object itself. This is what allows us to write:
std::cout << "Hello " << userName << " how are you?\n";


As such, the above can be simplified to:
if( std::cin >> someVariable ){   // std::cin is fine, read succeeded}else{   // something went wrong.   // could be end of file, or an error reading}



Restoring stream state is a little complex, but there is a nice alternative. Consider: no matter what the user enters, it will be text. So we can always store it in a std::string instance.

Once we have read the information as a string, we can parse it in memory, using the standard library class std::stringstream. As its name indicates, it allows you to treat a string as a stream, and use stream operations on it. It is a bit like a mixture of std::cin and std::cout, we can use both the stream insertion operator '<<' and the stream extraction operator '>>'.

We will read the data line by line, as that is how the console hands it to us. For example, to write a simplified "readInteger" function, we could do this:
#include <iostream>#include <string>// for std::stringstream#include <sstream>#include <stdexcept>int readInteger(const std::string &prompt){    std::string input;    std::cout << prompt;    while(std::getline(std::cin,input))    {        int result;        std::stringstream stream;        stream << input; // store the string in the stream        if( stream >> result ) // try read an integer from the stream        {            // success!            return result;        }        // if we get here, the user did not enter a number        // we let them know, and loop again.        std::cout << "You did not enter a number, try again\n";        std::cout << prompt;    }    // handle the error: end of file std::cin    // how can there be an end to std::cin you might ask    // most consoles provide a keyboard sequence to "end" the console input    // or the you can set your program to read the input from a physical file    // or even the output of another program    // for example, on windows, try typing CTRL and Z in the middle of this program    // now we are presented with a problem.    // every function must return a value (except main)... but what can we return?    // there is no right answer, if we return say 0    // there is no way for the code calling the function to tell    // if the user entered '0' or if the end of std::cin was reached    // in cases like this, we can throw an exception    // I don't really want to get into the specifics of exceptions    // However, I didn't want to present an illegal program to you    // =)    throw std::runtime_error("End of std::cin");}// example of useint main(){   int something = readInteger("Please enter a number: ");   std::cout << "You entered: " << something << '\n';}


Once you install the Boost C++ Library (it will happen eventually, when you are a little more experienced), you can use the handy helper function boost::lexical_cast. This function would make the implementation of the readInteger a bit simpler.

Summary: Correctly writing code to handle every possible input combination isn't exactly simple. I hope you can use the above as an example of how to make it work. In real programs, there are usually even more strict checks, for example the range of valid numbers might be restricted.
Quote:Original post by mreit
I'm very new to C++ and I am writing a console application just to get the hang of it. I was wondering, is there a way to check what the user puts into the console for the actual type of variable?

Example: If a user puts a char where they're supposed to put an int. This way if they enter the wrong type, then I can just make it so the program asks the user again instead of acting funny.


In this situation I always tell my program to get a character string from the users input. I then check to see if the input is a number or a string by looking at the ASCII values. If I want a number and a character is typed in, then I can loop back and tell the user to type in another value.
wow, thanks so much for all the help, I got it working!

This topic is closed to new replies.

Advertisement