tags:

views:

759

answers:

4

I am trying to write an if statement but cannot find the proper expression form to use. I'm thinking of writing something like this:

if ( var != type(int) )

However, I am unsure exactly how to go about doing this, and this method does not work.

Am I at least thinking along the right lines?

+18  A: 

It sounds like you're trying to overload a function:

void foo(int i)
{
    // stuff
}

void foo(float f)
{
    // stuff
}

int main(void)
{
    int i = 10;
    float f = 1.0f;

    foo(i); // calls foo(int)
    foo(f); // calls foo(float)
}

If you want int-special behavior and then something else in all other cases, you can use templates:

template <typename T>
void foo(T t)
{
    // T is something
}

template <>
void foo(int i)
{
    // for int's only
}

int main(void)
{
    int i = 10;
    float f = 1.0f;
    double d = 2.0;

    foo(i); // calls specialized foo
    foo(f); // calls generic foo
    foo(d); // calls generic foo
}


According to your comment ("Task at hand is a simple program: Take two user inputted integers and add them. Restrict input to integer only. I can do it in Python and I am thinking too along those lines. if num1 != type(int): print "You did not enter an integer, please enter a integer." else: continue"), you want something like this:

#include <iostream>

int main(void)
{
    int i;
    std::cin >> i;

    if (std::cin.fail())
    {
     std::cout << "Not valid!" << std::endl;
    }
    else
    {
     // ...
    }
}

This will notify invalid input such as "@#$", "r13", but does not catch cases such as "34fg", "12$#%", because it will read the int, and stop at "fg" and "$#%", respectively.

To check that, you will have to read in a line of input, and then try to convert that line into the type you want. (Thanks, litb). That means your question is more like this question:

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

int main(void)
{
    std::string input;
    std::getline(std::cin, input);

    std::stringstream ss(input);
    int i;
    ss >> i;

    if (ss.fail() || !(ss >> std::ws).eof())
    {
     std::cout << "Not valid!" << std::endl;
    }
    else
    {
     // ...
    }
}

This does the following: get input, and put it into a stringstream. Then after parsing the int, stream out any remaining white space. After that, if eof is false, this means there are left-over characters; the input was invalid.

This is much easier to use wrapped in a function. In the other question, the cast was re-factored away; in this question we're using the cast, but wrapping the input along with it.

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

bool parse_int(int& i)
{
    std::string input;
    std::getline(std::cin, input);

    std::stringstream ss(input);
    ss >> i;

    return !(ss.fail() || !(ss >> std::ws).eof());
}

int main(void)
{
    int i;

    if (!parse_int(i))
    {
     std::cout << "Not valid!" << std::endl;
    }
    else
    {
     // ...
    }
}

Or more generically:

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

template <typename T>
bool parse_type(T& t)
{
    std::string input;
    std::getline(std::cin, input);

    std::stringstream ss(input);
    ss >> t;

    return !(ss.fail() || !(ss >> std::ws).eof());
}

int main(void)
{
    int i;

    if (!parse_type(i))
    {
     std::cout << "Not valid!" << std::endl;
    }
    else
    {
     // ...
    }
}

This let's you parse other types with error checking.


If you're okay with exceptions, using lexical_cast (either from boost, or "faked", see the other question linked in-code [same as above link]), your code would look something like this:

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

/* Faked lexical-cast from question:
http://stackoverflow.com/questions/1243428/convert-string-to-int-with-bool-fail-in-c/
*/
template <typename T>
T lexical_cast(const std::string& s)
{
    std::stringstream ss(s);

    T result;
    if ((ss >> result).fail() || !(ss >> std::ws).eof())
    {
     throw std::bad_cast("Bad cast.");
    }

    return result;
}


template <typename T>
T parse_type(void)
{
    std::string input;
    std::getline(std::cin, input);

    return lexical_cast<T>(input);
}

int main(void)
{
    try
    {
     int i = parse_type<int>();
     float f = parse_type<float>();
    }
    catch (const std::exception& e)
    {
     std::cout << e.what() << std::endl;
    }
}

I don't think boost has a no-throw version of lexical cast, so we can make a true/false rather than exception version of this code by catching bad_cast's, as follows. Once again, this works with either boost or a custom lexical cast. (Anything that does a lexical cast and throws bad_cast):

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

/* Faked lexical-cast from question:
http://stackoverflow.com/questions/1243428/convert-string-to-int-with-bool-fail-in-c/
*/
template <typename T>
T lexical_cast(const std::string& s)
{
    std::stringstream ss(s);

    T result;
    if ((ss >> result).fail() || !(ss >> std::ws).eof())
    {
     throw std::bad_cast("Bad cast.");
    }

    return result;
}


template <typename T>
bool parse_type(T& t)
{
    std::string input;
    std::getline(std::cin, input);

    try
    {
     t = lexical_cast<T>(input);

     return true;
    }
    catch (const std::bad_cast& e)
    {
     return false;
    }
}

int main(void)
{
    int i;
    if (!parse_type(i))
    {
     std::cout << "Bad cast." << std::endl;
    }
}

Now it's back to a bool result, except we avoid code duplication by using existing lexical_cast functions.

You can of course choose which method you would like to use.

GMan
I am wondering how someone could give an answer to this at least to me ununderstandable question! +1 for the effort!!!
jdehaan
This makes MUCH more sense. The ws addition is also great.
SD
Thanks. Keep in mind, like others have been saying, C++ is strongly typed. These are all conversions from string-streams to respective types.
GMan
Your return statements in your example are very elaborate. Why not just do: return std::cin >> t;
Brian Neal
That will not error on trailing characters.
GMan
The `std::ws` approach works very well with `stringstream`, but it fails to work with `std::cin` connected to a terminal. It will wait when you press `enter`, eating it up, until you enter some non-whitespace and press enter again. When using the `std::ws` way, i always read a whole line into a string, and then do the remaining work on the stringstream.
Johannes Schaub - litb
@litb: It works with file streams, too. (Just nitpicking. Sorry.)
sbi
I've attempted to fix those things up, let me know if I messed anything up, like usual. :P Also, does `boost::lexical_cast` have a no-throw version?
GMan
+9  A: 

C++ is a statically-typed language, meaning that the type of a variable is known by the compiler at all times. In order to declare var therefore, you have to specify a type for it, which makes the if statement you posted a moot point. If you can describe a bit more the task you are trying to accomplish, perhaps there is another path to solve your problem.

fbrereto
Task at hand is a simple program:Take two user inputted integers and add them.Restrict input to integer only.I can do it in Python and I am thinking too along those lines.if num1 != type(int):print "You did not enter an integer, please enter a integer."else:continue
SD
In that case, I think you want to ask the question, "How can I make sure input coming from the user is restricted to an integer"? There are several ways to get input from the user in C++, and each way has techniques for verifying the user data you're getting.Also, it'll help to have more of the code you wrote in the body of your question.
fbrereto
You don't need to worry about restricting the input type to integer at runtime. Something like: int n; cin >> n; ensures that n is always an integer.
Nemanja Trifunovic
True- but I'm not familiar with how the OP is getting input from the user. e.g., if they're using getline they have to verify the data themselves. Your point is still valid given your example.
fbrereto
Yes - I was answering to the OP, didn't see your post :)
Nemanja Trifunovic
Quibble: C++ is a *statically* typed language. Whether it is "strongly" typed or not depends on your point of view. It's certainly stronger than C, but not as strong as, say, Haskell. However, your point is valid: the OP is acting like C++ is a dynamically typed language, which it certainly is not.
Daniel Pryden
@SD: As often, you should have asked "how to solve this problem", rather than "how to make this attempt working". Based on your comment above I think it's safe to say that you're on the completely wrong track. (In fact, that track's on the wrong planet.) In c++, in order to get correctly typed input, one uses streams. I suggest you ask another question, stating your problem and ask for ways to solve it.
sbi
@Daniel Pryden: Thanks for keeping me honest. Answer updated.
fbrereto
A: 

That is right, more information is needed, if you are looking for an equivalent of "instanceOf" operator of Java, there isn't one, unless you use RTTI and typeid.

Murali VP
A: 

Do you mean that you have a floating-point value and want to know if it's an integer or not?

In that case, try this:

#include <math.h>

//...

double x = 5.0;
if(round(x) == x) {
   // x has an integer value
}

Or, if the value is the result of some computation, there might be small rounding errors. Then try something like this:

double x = 4.99999999999;
if(abs(round(x) - x) < 1e-8)
CAdaker