我正在尝试构建一个函数,该函数将对用户对许多问题的响应执行完整性检查,每个问题理想情况下都是非零整数。如何构造一个能够接受任何数据类型的参数但只有一个参数的函数?例如:
bool SanityCheck(<type id> number)
其中<type id>
将涵盖任何数据类型。
答案 0 :(得分:6)
目前尚不清楚你到底想要什么。来自用户的未经验证的输入通常以字符串的形式出现。通常,您读入一个字符串,验证它是否具有所需的形式(例如,对于整数,所有数字)。如果它具有正确的形式,则将其转换为所需的类型,然后使用它。如果没有,则要求用户重新输入他们的数据,通常是提示“请输入1到10之间的整数”。
功能模板可以直接回答您提出的问题,但我很难想象它在您所描述的情况下会有任何帮助。函数模板通常用于必须执行某些在语法上相同的操作的情况。例如,它允许你添加两个数字,无论这些数字是short,int,long,float,double,long double等类型。这只能起作用,因为它们实际上都是数字,你可以合理使用+
将其中任何一个添加到一起。
当您处理某些未知输入时,虽然这不适用 - 您需要对数据进行足够的验证,以确保操作合理且有意义,然后再对其进行其他操作;通过比较(例如)7
和sunset
来获得有意义的结果非常困难。
答案 1 :(得分:3)
C ++是一种 静态类型 语言。变量的类型将是 在编译时修复 ,并且无法在运行时更改。但是,用户输入的内容仅为 在运行时 ,并且在编译时无法识别。因此你的问题毫无意义。
当您期望用户使用整数时,最好的方法是尝试读取整数,并检查是否成功:
int i;
std::cin >> i;
if(!std::cin)
throw "Stupid user blew it!"; // or some real error handling
然而,问题在于,一旦输入操作失败,输入流就会进入错误状态,而无法读取的数据会保留在输入缓冲区中。如果要优雅地处理此问题,则必须清除流的错误状态标志,并使其忽略输入缓冲区中的任何内容。
因此,有时可能更容易首先阅读字符串
std::string input;
std::cin >> input; // either read up to any whitespace, or
std::getline(std::cin, input); // newline, or
std::getline(std::cin, input, '\t'); // tab, or whatever you want
因为这总是成功,然后尝试将其转换为您需要的任何数据。这样做的方法是通过字符串流:
std::istringstream iss(input);
int i;
iss >> i;
现在您可以检查字符串流的状态
if(!iss)
如果转换失败,std::cin
仍然可用,错误的输入从其缓冲区读取。
然而,还有一个问题:如果用户输入'“42千”,那么这将不会发现错误。其余字符将在字符串流输入缓冲区中并默默忽略。因此,您通常需要为此类转换执行的操作是测试字符串流的缓冲区是否已完全读取,即:读取到达EOF。您可以通过调用iss.eof()
来检查这一点。但是,如果您读取整个行,最后可能会有额外的空格,您不希望转换失败,因此在检查EOF之前需要读取额外的空格: iss >> std::ws
。 (std::ws
是一个“吃”连续空格的流操纵器。)
到现在为止,转换看起来像这样:
std::istringstream iss(input);
int i;
iss >> i >> std::ws; // you can chain input
if(!iss.eof())
throw invalid_input(input);
当然,对于一次性转换来说,这是非常详细的,我不会完全发誓我的孩子的生活中没有一个很好的改进,我还没有想到。所以你至少想把它包装成一个函数并把它放到你的工具箱中重用它(如果你发现错误就改进它):
bool convert_to_int(const std::string& str, int& result)
{
std::istringstream iss(input);
iss >> result >> std::ws;
return iss.eof();
}
或者,任何类型的通用:
template< typename T >
bool convert_from_string(const std::string& str, T& result
{
std::istringstream iss(input);
iss >> result >> std::ws;
return iss.eof();
}
更好的方法是使用现成的现成解决方案。 Boost lexical_cast
就是int i;
do {
read string input
convert to int i
while(!conversion succeeded);
。
这是整个输入例程的骨架算法:
{{1}}
使用上面的位,您应该可以填写缺少的部分。
答案 2 :(得分:2)
使用模板:
template <typename T>
bool SanityCheck(T number);
完整性检查可能因不同类型而异。由于这是一个家庭作业,我不会发布任何更多的代码只是暗示您使用谷歌搜索术语“部分模板专业化”。
答案 3 :(得分:2)
好的,我想我现在已经得到了 想要的东西。
我想你的情况是这样的:
std::cin
)。int
。int
,请使用它。如果是这种情况,那么您不需要可以处理不同数据类型的函数,因为用户无法输入不同的数据类型,他只能输入字符,您必须选择要存储的数据类型。
我认为这就是你所需要的:
bool valid = false;
int input = 0;
while (!valid)
{
std::string inputStr;
std::cin >> inputStr;
valid = isInteger(inputStr);
if (!valid)
std::cout << "Please enter an integer." << std::endl;
else
input = atoi(inputStr.c_str());
}
std::cout << "You entered " << input << "!" << std::endl;
你将不得不自己写isInteger
,但希望你明白这一点。
答案 4 :(得分:1)
选项1:如果您希望它是单个函数,请使用boost :: variant
选项2:为您需要的所有类型重载此功能
答案 5 :(得分:0)
使您的函数成为模板函数可以实现此目的。
template<typename T>
bool SanityCheck(T number);
答案 6 :(得分:0)
我要求填写的大量在线调查不要求我输入数据,而只选择1到5的选项.1 =完全同意,5 =完全不同意。这似乎是一种收集用户输入的更有效方法,因为您可以完全控制数据类型,而我所要做的就是突出显示一个选项框。