I've found on this forum the following snippet witten by user Ben Voigt:
//forward declaration
template<typename T>
T getline_as(std::istream& s);
template<>
std::string getline_as<std::string>(std::istream& s)
{
std::string str;
std::getline(s,str);
return str;
}
template<typename T>
T getline_as(std::istream& s)
{
std::stringstream convert(getline_as<std::string>(s));
T value;
convert >> value;
return value;
}
I am looking for a way to handle possible failures of convert >> value;
. My goal would be
to iterate the request to the user to make it insert a given input correctly:
int main()
{
std::cout << "Please enter a number: ";
double number{getline_as<double>(std::cin)};
}
My idea was to create a do-while
loop inside getline_as
but I can't make it work.
template<typename T>
T getline_as(std::istream& s)
{
std::stringstream convert;
T value;
do
{
convert(getline_as<std::string>(s));
}
while(!(convert >> value));
return value;
}
CodePudding user response:
std::stringstream convert(...);
is a constructor call, but trying to do convert(...);
after the stream is created is illegal (it would require the stream to overload operator()
, which it doesn't do). convert = std::stringstream(...)
would work, but I'd just completely recreate the stream.
You also should use a read-only std::istringstream
, since you never write anything to it.
I also made some cosmetic changes and ended up with following:
template <typename T>
[[nodiscard]] T getline_as(std::istream &s);
template <>
[[nodiscard]] std::string getline_as<std::string>(std::istream &s)
{
std::string str;
std::getline(s, str);
return str;
}
template <typename T>
[[nodiscard]] T getline_as(std::istream &s)
{
while (true)
{
T value{};
std::istringstream convert(getline_as<std::string>(s));
if (convert >> value)
return value;
}
}