Owen L.
Owen L.

Reputation: 346

Is there a way to return to the top of a while loop without evaluating the condition expression in C++?

I have the following simple program to read two integer inputs and output their quotient:

static int getQuotient(int v1, int v2) {
    if (v2 == 0)
        throw runtime_error("Error: cannot divide by zero.");
    return v1 / v2;
}

int main()
{
    int v1, v2;
    cout << "Enter two integers." << endl;
    while(cin >> v1 >> v2) {
        
        int quotient;
        try {
            quotient = getQuotient(v1, v2);
        }
        catch (runtime_error err) {
            cout << err.what() << "\n" << "Please try again." << endl;
            continue;
        }
        cout << v1 << " / " << v2 << " = " << quotient << endl;
    }
}

As is, the program returns to the top of the while loop in main() when it encounters zero division. What I would like to do is have something like this in place of the current catch statement:

catch(runtime_error err) {
    cout << err.what() << endl;
    cout << "Enter a new value for v2." << endl;
    cin >> v2;
    continue;
}

So that the a new value is stored in v2 and the loop restarts. However, when the loop restarts new values are read into v1 and v2 which I don't want. Is there a way (besides goto) to return to the top of the loop without checking the condition? I know this is a specific use case but if there's an idiomatic way to solve this I'd rather know it.

Upvotes: 0

Views: 94

Answers (3)

Aykhan Hagverdili
Aykhan Hagverdili

Reputation: 29955

If you can, moving the input validation to a different routine of itself could improve the code:

#include <iostream>
#include <optional>
#include <utility>

std::optional<std::tuple<int, int>> 
get_v1_and_v2(std::istream& is = std::cin, std::ostream& os = std::cout)
{
    os << "Enter two integers.\n";
    int v1;
    if (!(is >> v1))
        return std::nullopt;

    int v2;
    while (true) {
        if (!(is >> v2))
            return std::nullopt;

        if (!v2)
            os << "v2 cannot be zero. Please try again.\n";
        else
            return std::tuple<int, int>{ v1, v2 };
    }
}

int 
main()
{
    while (auto const input = get_v1_and_v2()) {
        auto const [v1, v2] = *input;
        std::cout << v1 << " / " << v2 << " = " << (v1/v2) << '\n';
    }
}

Upvotes: 0

user6547518
user6547518

Reputation:

To avoid the record of input sometimes, you can use a bool value like this :

int main()
{
    int v1, v2;
    cout << "Enter two integers." << endl;
    bool repeat_without_input = false;

    while(repeat_without_input == true || cin >> v1 >> v2) {
        repeat_without_input = false;
        int quotient;
        try {
            quotient = getQuotient(v1, v2);
        }
        catch (runtime_error err) {
            cout << err.what() << "\n" << "Please try again." << endl;
            repeat_without_input = true;
            continue;
        }
        cout << v1 << " / " << v2 << " = " << quotient << endl;
    }
}

Upvotes: 0

perreal
perreal

Reputation: 97918

Maybe something like this:

while(cin >> v1) {    
    int quotient;
    while (true) {
      cin >> v2;
      try {
          quotient = getQuotient(v1, v2);
      }
      catch (runtime_error err) {
          cout << err.what() << "\n" << "Please try again." << endl;
          continue;
      }
      break;
    }
    cout << v1 << " / " << v2 << " = " << quotient << endl;
}

Upvotes: 5

Related Questions