C++用户输入限制,没有"goto"正确重试

vny*_*lng 2 c++ validation iostream goto istream

我有以下代码:

qstn:
  cout << "Input customer's lastname: ";
  getline(cin, lname);

  if (lname.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ") != string::npos) {
      cout << "You can only input alpha here!\n";
      cin.clear();
      goto qstn;
  } else if (lname.empty()) {
      cout << "Please enter your firstname!\n";
      cin.clear();
      goto qstn;
  }

  int lnamel = lname.length();
  int strl = str.length();
  int is = 0;

  for (int i = 1; i < strl;) {
      i++;
      is++;

      if (lname[i] == lname[is] && lname[i] == ' ' || lname[0] == ' ') {
          cin.clear();
          cout << "Please input your lastname properly!\n";
          goto qstn;
      }
  }
  // next question here
Run Code Online (Sandbox Code Playgroud)

我很难想到什么是避免goto语句的正确逻辑,因为我上大学时我正在使用它,但是有人说这根本不好用,因为它可能会破坏我的代码.

我尝试使用do while循环,但它并不像goto那样流畅.

请帮忙!

seh*_*ehe 6

这是我喜欢用的习语:

int i;

if (std::cin >> prompt("enter an integer: ", i))
{
    std::cout << "Read user input: " << i << "\n";
} else {
    std::cout << "Input failed (too many attempts). Eof? " << std::boolalpha << std::cin.eof() << "\n";
}
Run Code Online (Sandbox Code Playgroud)

这里prompt是一个智能输入操纵器,负责处理解析错误或流故障并重试.

它非常通用,所以实际上做了很多事情,但你不需要指出所有选项.当操纵器插入流中时,它会传递给do_manip成员:

template <typename Char, typename CharT>
friend std::basic_istream<Char, CharT>& operator>>(std::basic_istream<Char, CharT>& is, checked_input<T, Prompter>& manip) {
    return manip.do_manip(is);
}
Run Code Online (Sandbox Code Playgroud)

do_manip处理所有的逻辑,没有任何goto小号 :):

std::istream& do_manip(std::istream& is) {
    auto attempt = [this] { return infinite() || retries_ > 0; };

    while (attempt()) {
        if (!infinite())
            retries_ -= 1;

        prompter_(out_);

        if (is >> value_) {
            if (!run_validators(out_))
                is.setstate(is.rdstate() | std::ios::failbit);
            else
                break;
        } else {
            out_.get() << format_error_ << "\n";
        }

        if (attempt()) {
            is.clear();
            if (flush_on_error_)
                is.ignore(1024, '\n');
        }
    }

    return is;
}
Run Code Online (Sandbox Code Playgroud)

您可以看到在接受输入之前可以运行验证.

这是一个有点全面的演示:

Live On Coliru

int main() {
    using namespace inputmagic;

    int i;

    if (std::cin >> prompt("enter an integer: ", i)
            .retries(3)
            .flush_on_error(false)
            .format_error("I couldn't read that (Numbers look like 123)")
            .output(std::cerr)
            .validate([](int v) { return v > 3 && v < 88; }, "value not in range (3,88)")
            .validate([](int v) { return 0 == v % 2; })
            .validate([](int v) { return v != 42; }, "The Answer Is Forbidden")
            .multiple_diagnostics())
    {
        std::cout << "Read user input: " << i << "\n";
    } else {
        std::cout << "Input failed (too many attempts). Eof? " << std::boolalpha << std::cin.eof() << "\n";
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以看到它只接受有效的整数

  • 那些> 3和<88,
  • 那是偶数
  • 除了42(禁止号码)

在随后的重试中输入数字21,42和10时,您会得到:live

enter an integer: 21
Value not valid
enter an integer: 42
The Answer Is Forbidden
enter an integer: 10
Read user input: 10
Run Code Online (Sandbox Code Playgroud)

但是,如果你一直输入1:live

enter an integer: 1
value not in range (3,88)
Value not valid
enter an integer: 1
value not in range (3,88)
Value not valid
enter an integer: 1
value not in range (3,88)
Value not valid
Input failed (too many attempts). Eof? false
Run Code Online (Sandbox Code Playgroud)

或者,如果您从单行文件中读取:live

enter an integer: value not in range (3,88)
Value not valid
enter an integer: I couldn't read that (Numbers look like 123)
enter an integer: I couldn't read that (Numbers look like 123)
Input failed (too many attempts). Eof? true
Run Code Online (Sandbox Code Playgroud)