Reputation: 159
I am writing this function to ask for a particular input type. is_type just validates that the string recieved can be casted using stringstream to the desired type.
template<typename T>
T get_type(std::string prompt)
{
T output;
std::cout << prompt;
std::string Input;
while (std::getline(std::cin, Input) && !is_type<T>(Input))
{
std::cout << "Invalid input type. Please try again:\n"
<< prompt;
}
std::stringstream(Input) >> output;
return output;
}
The functions seems to work as desired except when I type ctrl + Z for example. What is the appropriate way to deal with this?
I added:
template<typename T>
T get_type(std::string prompt)
{
T output;
std::cout << prompt;
std::string Input;
while (std::getline(std::cin, Input) && !is_type<T>(Input))
{
std::cout << "Invalid input type. Please try again:\n"
<< prompt;
}
if (!std::cin)
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
output = get_type<std::string>(prompt) ;
return output;
}
std::stringstream(Input) >> output;
return output;
}
Which asks again for input after for example ctrl+Z Does that solve my problem of std::getline(std::cin, std::string) failing under kewyboard input from the user?
Also, why do I have to hit enter 2 times for the
output = get_type<std::string>(prompt) ;
line to run inside the if.
Upvotes: 3
Views: 1071
Reputation: 259
std::getline
could fail if you've used stdin
previously without clearing the failbit and if the input exceeds std::string::max_size
(see comment of Davis Herring).
Otherwise, I know of no way to let std::getline
fail except by EOF (^Z/^D
).
But, here is your code with some small improvements:
template<typename T>
T get_type(std::string prompt)
{
T output;
std::string input;
while(true)
{
std::cout << prompt;
std::getline(std::cin, input);
std::istringstream iss(input);
if(!std::cin)
{
std::cin.clear();
// std::clearerr(stdin);
}
else if(iss >> output && iss.eof())
return output;
std::cout << "Invalid input type. Please try again:\n";
}
}
As mentioned in the comments, it is necessary to use clearerr
on stdin
on some systems. If your system requires that, just uncomment std::clearerr(stdin);
.
Because of your 2x <Enter>
problem: the ignore statement is unnecessary. You just ignore the next input (that's why you have to hit <Enter>
twice).
Upvotes: 0