Search code examples
c++templatesstringstream

On the conversion from std::string type to template T type in C++


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;
}

Solution

  • 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;
        }
    }