Throw Key Word Needs If Structure

On line #8 I am at a lose of though on what to check for. I just need to know how a programmer goes about throwing an exception if one of the two, or both arguments in the function are point values. Other wise it just throws the exception without knowing when to do so.
#include <iostream>
#include <string>
using std::cout;
using std::string;

int add(int a, int b)
{
	if ()// <--------
	{
		throw string("float/double does not match int, possible loss of data");
	}

	return a + b;
}

int main()
{
	try
	{
		cout << add(1, 2) << '\n';// answer is 3.

		cout << add(1.5, 2) << '\n'; // this would cause a warning.

		cout << add(2, 2) << '\n';// answer is 4, but will never see the light of day unless line 22 is fixed.
	}
	catch (string error)
	{
		cout << "Error: " << error << '\n';
	}
	catch (...)
	{
		cout << "Default catch.\a\n";
	}
}// main.cpp

Comments

  • I think [icode]typeid[/icode] or the non-standard [icode]typeof[/icode] are related to your problem. However, I don't know if the problem can be solved from within your [icode]add[/icode] function... in C++ anyway. By the time you're inside the function, the arguments have been converted into integers and there's no way to know better.

    I don't think there's a good way to do it with plain old data types in C++ because they don't have any metadata. The only thing I can think of off the top of my head, which is probably a totally awful suggestion, is to have overloaded functions with identical names and different signatures which only throw. There might be a way to do it with templates; C++ isn't really my strong point.
    #include <iostream>
    #include <string>
    
    int add(int a, int b) {
    	return a + b;
    }
    
    int add(int a, float b) {
    	throw std::string("don't use floats");
    }
    
    int add(float a, int b) {
    	throw std::string("don't use floats");
    }
    
    int add(float a, float b) {
    	throw std::string("don't use floats");
    }
    
    int main(void) {
    	int i = 1;
    	float j = 2.0;
    	
    	try {
    		std::cout << add(i, j);
    	} catch (std::string s) {
    		std::cerr << s;
    	}
    	return 0;
    }
    
  • From that I was able to turn it into this. Both work just with a little extra beef now. I will play around with it some more latter, but you are right there might not be a better way.
    #include <iostream>
    using std::cerr;
    using std::cout;
    using std::exception;
    using std::runtime_error;
    
    int add(int a, int b)
    {
    	return a + b;
    }
    
    int add(int a, float b)
    {
    	throw runtime_error("Do not use floats.");
    }
    
    int add(float a, int b)
    {
    	throw runtime_error("Do not use floats.");
    }
    
    int add(float a, float b)
    {
    	throw runtime_error("Do not use floats.");
    }
    
    int main()
    {
    	try
    	{
    	        cout << add(1, 1) << '\n';// Answer equals 2.
    
    		cout << add((float) 1.5, 1) << '\n';// Answer is 2.5 but throws an exception.
    
    		cout << add(1, 2) << '\n';// Answer equals 3.
    	}
    	catch (exception &ex)
    	{
    		cerr << ex.what() << '\n'
    			 << __FILE__ << ' ' << __LINE__ << '\n';
    	}
    }// main.cpp
    
  • Keep holding out for a reply from someone else. I feel like there's an answer for you, but I just don't know it.
  • What exactly are you trying to achieve? The simple answer is to never pass in a float. If at some point you are taking user input, and that is what you are tying to handle, then check your input before even calling the add function. There is no need for exception handling here at all.

    http://stackoverflow.com/questions/18728754/checking-input-value-is-an-integer
  • I am just trying to come up with my own exception example. Something I can understand. The more I look at this code the more I realize if it was a template it would not matter what the programmer, or user of the end product was inputting it could handle it. As for what an exception could do from there I am guessing nothing more then watching out for a division by zero. Even then there are ways of handling input to watch out for that. However there is no one size fits all, or be all end all of programs to do things like this or anything for that matter. We all need to know something about everything, and not just what we are comfortable with.
    #include <iostream>
    using std::cerr;
    using std::cout;
    using std::exception;
    using std::runtime_error;
    
    int division(int a, int b)
    {
    	if (b == 0)
    	{
    		throw runtime_error("Do not divide by zero.");
    	}
    
    	return a / b;
    }
    
    int main()
    {
    	try
    	{
    		cout << division(1, 0) << '\n';
    
    		cout << division(2, 1) << '\n';
    	}
    	catch (exception &ex)
    	{
    		cerr << "Error: " << ex.what() << '\n'
    			 << __FILE__ << ' ' << __LINE__ << '\n';
    	}
    }// main.cpp
    
  • King wrote:
    The simple answer is to never pass in a float. If at some point you are taking user input, and that is what you are tying to handle, then check your input before even calling the add function. There is no need for exception handling here at all.
    This thought crossed my mind, but the programmer is not necessarily the only one who will ever use the program. He could release a library with this function inside for someone to use blindly. Obviously this is a trivial example, but somewhere out there is a use for preemptive type-checking.
    As for what an exception could do from there I am guessing nothing more then watching out for a division by zero. Even then there are ways of handling input to watch out for that.
    You are correct.

    Tied in to what I said above, the programmer can't always help what the input is. This is where exceptions shine. I couldn't wrap my head around how exceptions were useful at all (as opposed to error codes/debug messages) until I got a real job in the field.
  • Just recently I have noticed that in line #25 it is possible to take out the address operator. With or without it the code works the same. Which should it be?
  • In this case it makes sense to leave it. Without it, it will make a copy of the exception object instead of just passing a reference to it (i.e. it saves memory to leave it).
Sign In or Register to comment.