为什么对于complex<double>类型的operator>>,如果遇到EOF不会设置eofbit?

9
我正在尝试从文件(或任何std :: istream)中读取尽可能多的std :: complex 。如果操作失败,我会检查ios :: eof()。如果它没有被设置,我会假设在解析数据时出现了错误,并且可以向用户报告输入文件存在错误。这个方案适用于double,但是在复数上却失败了。为什么?
以下是一些用于重现问题的代码:
std::istringstream istr("4 1.2");
std::complex<double> val;

while( istr >> val )
        std::cout << " val = " << val << std::endl;

std::cout << "flags: eof=" << istr.eof() << " fail=" << istr.fail() << " bad=" << istr.bad() << std::endl;

输出为:

输出结果为

 val = (4,0)
 val = (1.2,0)
 flags: eof=0 fail=1 bad=0

如果我将std :: complex<double>替换为double,它会按预期工作,产生
 val = 4
 val = 1.2
 flags: eof=1 fail=1 bad=0

这个问题出现在libstdc++中,但似乎在libc++中可以运行: 使用g++在coliru上运行 使用clang++和libc++在coliru上运行 编辑 我发现了一个2013年的错误报告,但问题似乎仍然存在,而该库非常常见。有没有办法让它对任何人都有效,而不必编写自己的解析器?

为什么需要编写自己的解析器?为什么不直接从流中读取两个double,并使用它们构造一个complex<double>? - Peter
因为我需要complex<double>提供的序列化的灵活性。它可以识别double(double)(double,double) - dennis
整个“complex”提取器的业务极其未详细说明,但这里的实现明显也有问题。 - T.C.
1个回答

1

它源于标准措辞:

[complex.ops]
12 效果:提取一个复数x,形式为:u(u)(u,v),其中u是实部,v是虚部(27.7.2.2)。
13 要求:输入值应可转换为T。如果遇到错误输入,则调用is.setstate(ios_base::failbit)(可能抛出ios::failure(27.5.5.4))。
14 返回is
15 备注:这个提取是作为一系列更简单的提取来执行的。因此,对于每个更简单的提取,空格的跳过被指定为相同的。

特别是它没有明确指定在任何情况下都应该设置eofbit。即使备注也没有指定执行哪些操作以及它们的语义是什么。有一个缺陷报告,建议通过指定操作的语义来解决问题,并且如果我们很幸运,它将成为C++17的一部分。

"...并且分辨率应该包含在C++17中" 你比我更乐观。让我们看看LWG对此的处理。 - T.C.
@T.C. Oh,你说得对。我不知道为什么会把“拟议的解决方案”误读成“已解决”。 - Revolver_Ocelot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接