Способы std :: getline (std :: cin, string) могут не работать с клавиатуры - PullRequest
0 голосов
/ 09 февраля 2019

Я пишу эту функцию для запроса определенного типа ввода.is_type только подтверждает, что полученная строка может быть приведена с использованием stringstream к желаемому типу.

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

Функции, кажется, работают должным образом, за исключением случаев, когда я, например, набираю ctrl + Z.Как правильно решить эту проблему?

Я добавил:

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

, который снова запрашивает ввод после, например, ctrl + Z Решает ли это мою проблему с std :: getline (Сбой std :: cin, std :: string) при вводе пользователем кода на Kewyboard?

Кроме того, почему я должен нажать 2 раза, чтобы строка

output = get_type<std::string>(prompt) ; 

запускалась внутриесли.

1 Ответ

0 голосов
/ 09 февраля 2019

std::getline может произойти сбой, если вы ранее использовали stdin без очистки битов сбоя и если входное значение превышает std::string::max_size (см. Комментарий Дэвиса Херринга).В противном случае, я не знаю способа, чтобы std::getline потерпел неудачу, кроме как с помощью EOF (^Z/^D).

Но вот ваш код с некоторыми небольшими улучшениями:

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

Как уже упоминалосьв комментариях необходимо использовать clearerr на stdin на некоторых системах.Если ваша система требует этого, просто раскомментируйте std::clearerr(stdin);.

Из-за вашей проблемы 2x <Enter>: оператор ignore не нужен.Вы просто игнорируете следующий ввод (вот почему вы должны дважды нажать <Enter>).

...