概述

在学习 C/C++ 的一开始,我们就接触到基本的输入输出,例如printf/scanf或者cout/cin, 但是在涉及用户输入时总是存在可靠性问题:我们无法确保用户输入的信息是合法的,比如要求输入一个数字,但是用户提供的是一串字符串等等,或者要求数字满足一定范围等,我们只能每次手动在外层加一个循环和判断条件,非常繁琐。 在本文中实现了一个简单的获取安全输入的封装SafeInput,使得在编程中尽可能摆脱这类涉及用户输入参数的处理细节。

使用示例

  1. 指定获取一个int类型的值,要求大于 0 且小于 5,如果输入不满足要求,则会提示重新输入
1
2
int s = SafeInput().next<int>("Please input a int in (0,5): ",
[](int p) { return 0 < p && p < 5; });
  1. 指定获取一个double类型的值,并且在获取值之后会回显这个值,需要用户继续输入Y确认,否则提示重新输入
1
double d = SafeInput().next<double>("Please input a double: ", true);
  1. 提示用户输入Y|N|Q进行确认,输入Y|N将通过布尔变量返回,输入Q则会使用exit(0)直接退出程序
1
bool s = SafeInput().confirm("Continue or exit?");
  1. 程序暂停并等待,直到获取到回车后,程序继续执行
1
SafeInput().pause();

使用要求

示例中的 1 和 2 体现了最主要的用法,其中输入的合法性检查和对输入的再次手动确认都是可选的,一共有四种组合,函数原型依次为

1
2
3
4
5
6
7
8
9
10
11
template <typename T, typename CheckerType>
T next(const std::string &msg, CheckerType checker,bool confirm) const;

template <typename T>
T next(const std::string &msg, bool confirm) const;

template <typename T, typename CheckerType>
T next(const std::string &msg, CheckerType checker) const;

template <typename T>
T next(const std::string &msg) const;

示例中的 3 和 4 则是作为常用情景被直接提供

1
2
3
4
5
bool confirm(const std::string &msg) const;

bool confirm() const;

void pause() const;

注意:

  • 建议使用 lambda 表达式提供合法性检查,要求返回布尔类型的检查结果,指定的输入类型T则通过函数模板提供。
  • 每一次的输入都处于循环之中,无论输入成功,还是失败再次输入,都会清空缓冲区,因此不支持连续的输入,这是出于可靠性的考虑。
  • 用于判断的特殊字符(Y|N|Q)均不区分大小写。
  • 默认会将所有的提示语输入到std::cout,并且从std::cin获取用户输入,但是也支持在构造函数中指定其它的输入和输出流。
1
2
3
4
5
SafeInput() : m_in(std::cin), m_out(std::cout) {}

explicit SafeInput(std::istream &in) : m_in(in), m_out(std::cout) {}

SafeInput(std::istream &in, std::ostream &out) : m_in(in), m_out(out) {}

完整的使用示例如下

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include "safe_input.hpp"

int main(int argc, char *argv[]) {
auto s = SafeInput().next<int>("Please input a int in (0,5): ",
[](int p) { return 0 < p && p < 5; });
std::cout << "s=" << s << "\n";

auto d = SafeInput().next<double>("Please input a double: ", true);
std::cout << "final: d=" << d << "\n";

auto p = SafeInput().next<bool>("input a bool: ", true);
std::cout << "final: p=" << p << "\n";

SafeInput().confirm("Continue or exit(2)?");

SafeInput().pause();

return 0;
}

源代码

源文件放置在Github仓库:cpptoybox