-1

Hello I'm relatively new to operator overloading, but I do believe its the answer to a problem i've been facing in almost every program I make. My goal is to overload std::cin >> int_var so that it can only accept integer inputs, and if it detects that an input besides a int was entered it puts the user into a loop until the input is an int.

This is what I've came u with so far

#include <iostream>

std::istream& operator>> (std::istream& Cin, int *var)
{
  int var2;
  if(!Cin >> var2)
  {
    std::cout << "Invalid input!";
  }
  return Cin;
}

int main() {
  int var;
  std::cin >> var;
  std::cout << var;

}  

Note: This code snippet is just to see if I can detect an invaild input. It don't need it to include the loop just yet.

  • you need to look at Cin.bad() and Cin.reset() – pm100 Jan 22 '22 at 23:16
  • 3
    What if the user enters something like `"6sdfj23jlj"`? Should that be accepted as valid input for the number `6`, as the stream extraction operatior `>>` currently does? Or should it reject the input and reprompt the user for new input? If it is the latter, then you are probably looking for line-oriented input such as that provided by [`std::getline`](https://en.cppreference.com/w/cpp/string/basic_string/getline), instead of input like the stream extraction operator. In that case, it does not make much sense to override the stream extraction operator `>>`. You should rather write a function. – Andreas Wenzel Jan 22 '22 at 23:19
  • If you actually try the shown code, you will discover that the overloaded operator will not even be called. This is an operator overload for a pointer to an `int`, instead of an `int`. The C++ library already has a operator overload for this, and you're not going to override it, this easily. – Sam Varshavchik Jan 22 '22 at 23:23
  • @AndreasWenzel perfect thank you, I'll experiment around with that. – Cod Pod Tracks Jan 22 '22 at 23:25
  • @CodPodTracks: In addition to the function `std::getline`, you will probably also need the function [`std::stoi`](https://en.cppreference.com/w/cpp/string/basic_string/stol). Also, in the second code snippet of [this answer of mine to another question](https://stackoverflow.com/a/69636446/12149471), I wrote a function `get_int_from_user` in C. This seems to be exactly what you are looking for, but in C instead of C++. I'm not sure if this will help you. it may confuse you more than help you, because C-style programming is very different from modern C++, even if C is mostly compatible with C++. – Andreas Wenzel Jan 22 '22 at 23:34
  • @CodPodTracks: I have now rewritten my C function `get_int_from_user` to C++, and posted it as an answer. – Andreas Wenzel Jan 23 '22 at 00:32
  • One point to consider is that `>>` is also used to read from files; in that situation, making it a loop and/or prompting the user wouldn't be appropriate... what can they do about the file at that point? – Jiří Baum Jan 23 '22 at 05:48

3 Answers3

2

The correct way to get user input is to:

  1. read a string
  2. attempt to convert the string to int (or whatever)
  3. if the conversion fails, you should either:
    • ask and try again, only IFF user is known to be a human
    • terminate (require your users to give valid inputs)

This is because the user will always press Enter after every input prompt.

Variations on this question abound. Here’s my last answer, complete with a working example.

Dúthomhas
  • 8,200
  • 2
  • 17
  • 39
0

I don't know if you can. What you need to do is validate any and all user input. No matter what the application is never trust the user.

So you just need to check if the value you get is an integer then you can call your function and if it isn't a integer then ask for the input again and tell them why it was wrong like "Input only accepts integers".

Bobthemob
  • 1
  • 1
0

I don't recommend that you attempt to overload the stream extraction operator >> in order to significantly change its behavior. It would make more sense to create your own function.

The stream extraction will accept user input such as "6sdfj23jlj" as valid input for the number 6. If you instead want to reject such input and reprompt the user for new input in such a case, then it would probably make more sense to use line-oriented input such as std::getline, instead of the stream extraction operator >>.

After reading in a string with std::getline, you can attempt to convert it to an integer using the function std::stoi.

In the following program, I have created a function get_int_from_user, which will repeatedly ask the user for input, until the input is valid.

#include <iostream>
#include <string>
#include <cctype>

int get_int_from_user( const std::string& prompt )
{
    std::string line;
    std::size_t pos;
    int i;

    //repeat forever, until an explicit return statement or an
    //exception is thrown
    for (;;) //equivalent to while(true)
    {
        //prompt user for input
        std::cout << prompt;

        //attempt to read one line of input from user
        if ( !std::getline( std::cin, line ) )
        {
            throw std::runtime_error( "unexpected input error!\n" );
        }

        //attempt to convert string to integer
        try
        {
            i = std::stoi( line, &pos );
        }
        catch ( std::invalid_argument& )
        {
            std::cout << "Unable to convert input to number, try again!\n";
            continue;
        }
        catch ( std::out_of_range& )
        {
            std::cout << "Out of range error, try again!\n";
            continue;
        }

        //The remainder of the line is only allowed to contain
        //whitespace characters. The presence of any other
        //characters should cause the entire input to get rejected.
        //That way, input such as "6sdfj23jlj" will get rejected,
        //but input with trailing whitespace will still be accepted
        //(just like input with leading whitespace is accepted by
        //the function std::stoi).
        for ( ; pos < line.length(); pos++ )
        {
            if ( !std::isspace( static_cast<unsigned char>(line[pos]) ) )
            {
                std::cout << "Invalid character found, try again!\n";

                //we cannot use "continue" here, because that would
                //continue to the next iteration of the innermost
                //loop, but we want to continue to the next iteration
                //of the outer loop
                goto continue_outer_loop;
            }
        }

        //input is valid
        return i;

    continue_outer_loop:
        continue;
    }
}

int main()
{
    try
    {
        int i = get_int_from_user( "Please enter a number: " );

        std::cout << "Input was ok, you entered: " << i << '\n';
    }
    catch ( std::runtime_error& e )
    {
        std::cout << "Runtime error: " << e.what() << '\n';
    }
}

This program has the following behavior:

Please enter a number: Test
Unable to convert input to number, try again!
Please enter a number: 3000000000
Out of range error, try again!
Please enter a number: 6sdfj23jlj
Invalid character found, try again!
Please enter a number: 633245183
Input was ok, you entered: 633245183

The code above uses one goto statement. Under most circumstances, you should avoid using goto, but for breaking out of nested loops, it is considered appropriate.

Andreas Wenzel
  • 22,760
  • 4
  • 24
  • 39
  • I often recommend people write little functions to get specific kinds of input from the user, and put all the unfriendly I/O stuff there so that the calling code can be much cleaner, so, nice job! You can get rid of the loop and `goto` using `first_not_of( " \f\n\r\t\v", pos )`. – Dúthomhas Jan 23 '22 at 00:46
  • @Dúthomhas: Yes, I agree that this makes code a lot cleaner. Regarding using `first_not_of` instead of [`std::isspace`](https://en.cppreference.com/w/cpp/string/byte/isspace): I am not sure if it is good to hard-code the whitespace characters into the program, because the advantage of using `std::isspace` is that it is affected by the current [locale](https://en.cppreference.com/w/cpp/locale/setlocale). The current locale could specify additional characters that are to be considered whitespace characters. However, I don't have much experience dealing with non-default locales. – Andreas Wenzel Jan 23 '22 at 01:19
  • Outside of Unicode NEL and NBSP, I am unaware of any locale where a `char` may include space characters not listed. – Dúthomhas Jan 23 '22 at 01:30