首页 > 解决方案 > EOF 上的 std::ws 行为

问题描述

我偶然发现了不同编译器之间的行为差​​异。假设以下代码:

#include <sstream>
#include <iostream>

using namespace std;

int main() {
    istringstream ss("100");
    int val;
    ss >> val;
    cout << "fail: " << ss.fail() << " eof: " << ss.eof() << endl;
    ss >> std::ws;
    cout << "fail: " << ss.fail() << " eof: " << ss.eof() << endl;
}

VS2019 和 Clang 10 使用 libc++ 生成的输出是:

fail: 0 eof: 1
fail: 1 eof: 1

而带有 libstdc++ 的 VS2015 和 GCC 10.2 生成:

fail: 0 eof: 1
fail: 0 eof: 1

所以问题是哪个实现是正确的?std::ws当 eofbit 已经设置时应该设置失败位吗?

我查过std::ws标准,上面写着:

30.7.4.4 标准 basic_istream 操纵器 [istream.manip]

模板<class charT, class traits> basic_istream<charT, traits>& ws(basic_istream<charT, traits>& is);

效果:表现为无格式输入函数 (30.7.4.3),但它不计算提取的字符数,也不影响后续调用 is.gcount() 返回的值。在构造一个哨兵对象后,只要下一个可用字符 c 是空格或直到序列中没有更多字符,就会提取字符。空白字符的区分标准与 sentry::sentry (30.7.4.1.3) 使用的标准相同。如果 ws 因为没有更多可用字符而停止提取字符,它会设置 eofbit,但不会设置 failbit。

因此,最后明确声明它设置 eofbit,但在没有可用字符时不设置 failbit。但它也表现为一个未格式化的输入函数,它创建一个sentry对象。然后sentry构造函数将is.setstate(failbit)is.good()为 false 时调用。所以在某种程度上,两种实现都不是完全错误的。更好地理解标准的人可以澄清哪种行为是正确的以及我应该在哪里提交错误?

标签: c++stl

解决方案


failbit应该设置。它是由sentry对象完成的,ws首先是什么构造。

[istream::sentry]/2
explicit sentry(basic_istream<charT, traits>& is, bool noskipws = false);
效果:如果is.good()false,则调用is.setstate(failbit). 除此以外, ...


推荐阅读