-2

If I were to ask the user a question and the response can be either a string or an int, I would have to determine if it were an int or a string before I can pass the input to a variable right? How would I do that?

  • Strings are a superset of numbers, at least in terms of holding the data. – chris Mar 27 '15 at 00:47
  • http://en.cppreference.com/w/cpp/string/byte/isdigit -- `Isdigit()` – Jagannath Mar 27 '15 at 00:48
  • If you exclusively want `int`, you can use the `input bits –  Mar 27 '15 at 00:50
  • I'd say this answer leads you to one of the best viable approaches: [How to test whether stringstream operator>> has parsed a bad type and skip it](http://stackoverflow.com/questions/24504582/how-to-test-whether-stringstream-operator-has-parsed-a-bad-type-and-skip-it). Anyway, considered that there are so many approaches available to solve your problem (dependent from more certain use cases), it's not possible to give a concise answer at all. – πάντα ῥεῖ Mar 27 '15 at 00:53
  • @jafar _"the `input bits "_ What are these? That's new to me. Please explain! – πάντα ῥεῖ Mar 27 '15 at 00:55
  • http://www.cplusplus.com/reference/ios/ios/fail/ –  Mar 27 '15 at 00:58
  • I'm kind of surprised no one has mentioned `std::stoi`. – chris Mar 27 '15 at 01:00
  • From your question, if your program asks "how old are you?" is `20` or `twenty` correctly possible answers? –  Mar 27 '15 at 01:02
  • @jafar I much prefer http://en.cppreference.com/w/cpp/io/basic_ios/fail. But that's merely opinion based, and you should extend about the actual behavior a bit more in your answer for my taste. – πάντα ῥεῖ Mar 27 '15 at 01:05

5 Answers5

2

The normal way is to read in a string, check if the string contains an integer, and then if it does, convert the contents to an integer. The goal of the if(inttest>>myint) is to attempt to read into an integer. If it succeeds, the input-string must have been an integer. If it fails, it wasn't an integer.

std::mystring;
int myint;

std::cin >> mystring;
std::istringstream inttest(mystring);
if (inttest>>myint) {
    //it's an integer
    std::cout << myint;
} else {
    //it's a string
    std::cout << mystring;
}

The reason for the additional istringstream is that cin >> var eats the input, so if it fails to convert, it is already gone. Thus the need to cache the input locally, attempt to convert it, and if that failed then use the cached value as-is.

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • why there the need for an additional `istrtingstream`? I thought the result of `std:cin>>var` should be enough. – vsoftco Mar 27 '15 at 00:49
  • 1
    `cin >> var` eats the input, so if it fails to convert, it is already gone. Thus the need to cache the input locally, attempt to convert it, and if that failed then use the cached value as-is. – Remy Lebeau Mar 27 '15 at 01:02
  • This method doesn't seem to work for me (maybe I'm doing it wrong) `int main() { string input; //get the input from the user cout << "Enter either an int or a string "; cin >> input; istringstream inttest(input); if (inttest>>input) { //it's an integer cout << "it's an int"; } else { //it's a string cout << "it's a string"; } return 0; }` – Pierre Gaboriau Mar 27 '15 at 01:24
  • @PierreGaboriau: the goal of `if(inttest>>myint)` is to attempt to read into an _integer_. If it succeeds, the input-string must have been an integer. If it fails, it wasn't an integer. Your code there reads into a string instead of an integer, which always succeeds, because a string can read anything. – Mooing Duck Mar 27 '15 at 16:24
1

You could read the input with string::getline() and then use the string as input string stream to try to read a number.

bool got_string = true; 
string line;
int number;
if (getline(cin, line)) {  // if read is successful 
    istringstream str(line);
    if (str >> number)         // and if the format corresponds to a number
        got_string = false;
}
Christophe
  • 68,716
  • 7
  • 72
  • 138
0

This depends on what you accept. If the answer should be only an int, then you can test the result of if(cin>>var) (where var is int). If it is false, then the readout was un-successful, which means you din't introduced a valid int.

In other words, the stream "detects" whether its last operation was successful or not.

vsoftco
  • 55,410
  • 12
  • 139
  • 252
0

I think this provides for string and integer answers.

#include <iostream>
#include <sstream> 
#include <string>
using namespace std;

int main()
{
    int y;
    string answer;
    cout<<"how old are you ";
    getline(cin,answer);

    stringstream ss;
    ss<<answer;

    //check if its int
    if(ss>>y)
        cout<<"you are "<<y<< "(int)"<<endl;
    else    //its string
        cout<<"you are "<<answer<<" (string)"<<endl;

    return 0;
}
0

I don't believe this is the best way to do this, but a comment on an existing answer caught my eye...

cin >> var eats the input, so if it fails to convert, it is already gone. Thus the need to cache the input locally, attempt to convert it, and if that failed then use the cached value as-is. – Remy Lebeau

...so I thought I'd show that it is sometimes possible to recover from a parsing error - resetting the istream so further input can be attempted. Using this approach, you can first try to read an int, and if that fails read a word of text into a std::string. It's important to do it that way because reading say "46" into a std::string works just fine so doesn't tell you it could have been parsed as an int, but reading "fifty" into an int fails then you know you'll have to try getting it into a std::string.

Though not relevant for inputting an age, more generally one negative with this approach is - well - negatives. Trying to parse "-five" as an int will consume the - then fail, leaving only the five to be parsed as a std::string. Depending on the type of stream in use, you may be able to record the stream position with .tellg, then if it fails restore the position with seekg.

Anyway, enough blabbing - here's some code, where I use one std::istringstream in place of std::cin so I can run it on ideone.com without manual input, but the point is that it doesn't need an extra std::istringstream with a copy of a line of input:

#include <iostream>
#include <sstream>
#include <string>

void f(const char* p)
{
    std::istringstream iss(p);
    int num;
    if (iss >> num)
        std::cout << num << " (an int)\n";
    else
    {
        iss.clear(); // recover from parsing int failure above
        std::string word;
        if (iss >> word)
            std::cout << word << " (a string)\n";
    }
}   

int main()
{
    f("five");
    f("35");
}

Output:

five (a string)
35 (an int)

Available on ideone.com

Tony Delroy
  • 102,968
  • 15
  • 177
  • 252