9

I'm trying to read as many std::complex<double> as possible from a file (or any std::istream). If the operation fails, I check for ios::eof(). If it hasn't been set, I assume that there was an error in parsing the data, and I can report to the user that the input file has errors. This scheme works for double, but somehow it fails on complex numbers. Why?

Here is some code to reproduce the problem:

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;

The output is

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

If I replace std::complex<double> with double, it works as expected, yielding

 val = 4
 val = 1.2
 flags: eof=1 fail=1 bad=0

This problem occurs with libstdc++, but it seems to work with libc++:

run on coliru with g++

run on coliru with clang++ and libc++

EDIT I found a bug report from 2013 but the problem still seems to be there, and the library is quite common. Is there a way for me to make it work for anybody without having to write my own parser?

dennis
  • 192
  • 7
  • Why would you need to write your own parser? Why not simply read two `double`s from the stream, and use those to construct a `complex`? – Peter Jun 16 '16 at 13:15
  • Because I need the flexibility of serialization that complex offers. It recognizes `double`, `(double)` and `(double,double)` – dennis Jun 16 '16 at 13:18
  • The whole `complex` extractor business is extremely underspecified, but the implementation here is clearly broken too. – T.C. Jun 16 '16 at 13:20

1 Answers1

1

It stems from standard wording:

[complex.ops]
12 Effects: Extracts a complex number x of the form: u, (u), or (u,v), where u is the real part and v is the imaginary part (27.7.2.2).
13 Requires: The input values shall be convertible to T. If bad input is encountered, calls is.setstate(ios_base::failbit) (which may throw ios::failure (27.5.5.4)).
14 Returns: is.
15 Remarks: This extraction is performed as a series of simpler extractions. Therefore, the skipping of whitespace is specified to be the same for each of the simpler extractions.

In particular it does not specify that it should set eofbit in any case. Even remark does not specify what operations are performed and what their semantic is. There is a Defect Report about it, which suggest resolution by specifying semantic of operation and, if we are lucky, it will make its way to C++17.

Revolver_Ocelot
  • 8,609
  • 3
  • 30
  • 48