std::getline(std::cin, string) 可能因键盘输入失败的方式

Ways std::getline(std::cin, string) can fail from keyboard input

本文关键字:std 键盘 输入 失败 方式 getline cin string      更新时间:2023-10-16

我正在编写此函数以请求特定的输入类型。 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( 失败的问题?

另外,为什么我必须按回车键 2 次才能

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

在 if 内运行的行。

如果您以前使用过stdin而没有清除故障位并且输入超过std::string::max_size,则std::getline可能会失败(请参阅Davis Herring的评论(。否则,我知道除了EOF(^Z/^D(之外,没有办法让std::getline失败。

但是,这是您的代码,其中包含一些小的改进:

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

如评论中所述,有必要在某些系统上stdin上使用clearerr。如果您的系统需要,只需取消注释std::clearerr(stdin);

由于您的 2 倍<Enter>问题:忽略语句是不必要的。您只需忽略下一个输入(这就是为什么您必须点击两次<Enter>(。