Vahagn
Vahagn

Reputation: 4850

std::setfill and std::setw for input streams?

Consider this code:

int xx;
std::cin >> std::setfill('0') >> std::setw(4) >> xx;

When sending 12 to the standard input I am expecting the value of xx to be 1200 and when sending 12345 I am expecting it to be 1234.

However, it seems std::setfill and std::setw have no effect and I am getting 12 and 12345 respectively.

Is this a bug or it is according to the standard? Is there a good way to get the expected functionality?

Also note, when I change the type of xx to be std::string the std::setw takes effect while std::setfill still doesn't.

My compiler is gcc-7.0.1.

Upvotes: 3

Views: 2108

Answers (3)

Jonathan Wakely
Jonathan Wakely

Reputation: 171403

Due to historical accident, GCC and MSVC support using setfill with an istream. It will call ios::fill(c) to store the fill character, but that is never used by any of the extraction functions that read values from an istream. So you can compile it, but it doesn't do what the OP expects.

In the olden times, most I/O manipulators worked with both input and output streams. In mid-1996 (i.e. prior to the original C++98 standard) the specification for I/O manipulators was changed by issue 27-652 in N0958 and issue 27-651 in N0964.

It seems that the iostreams implementations in GCC and MSVC were never adjusted for the change that made setfill only apply to ostreams. The Clang library (libc++) was written from scratch around 2010 and so was implemented according to the final standard, without any remnants of draft standards from the 1990s.

Interestingly, (at least some editions of) the book Standard C++ IOStreams and Locales: Advanced Programmer's Guide and Reference by Angelika Langer and Klaus Kreft also said that setfill worked with both input and output streams. So it wasn't only GCC and Dinkumware that didn't get the memo about the change.

Upvotes: 1

lukeg
lukeg

Reputation: 4399

According to C++ standard, setfill pertains to output stream. As for the setw, it works for input stream when used together with char* or string. For example, following program outputs abcd for input string abcdef (and 1234 for 123456):

string a;
cin >> setw(4) >> a;
cout << a;

Upvotes: 3

Potatoswatter
Potatoswatter

Reputation: 137910

setw and setfill are not applied so universally.

It sounds like you want to imitate the effect of formatting the given input in a fixed-width column, then re-reading it. The library does provide tools for exactly that:

int widen_as_field( int in, int width, char fill ) {
    std::stringstream field;
    field << std::setw( width ) << std::setfill( fill );
    field << std::setiosflags( std::ios::left );
    field << in;
    int ret;
    field >> ret;
    return ret;
}

Demo.

This function will not trim 12345 to 1234, though. That would take another conversion through string.

Upvotes: 1

Related Questions