Why does std::num_put take the ios_base parameter by non-const reference?

206 views Asked by At

I'm experimenting with the iostreams / locale numeric facet and I've hit something quite curious:

The "canonical example" of using the std::num_put facet to directly format a number goes like this:

std::string f(double value) {
    using namespace std;
    stringstream ss;
    num_put<char> const& npf = use_facet<num_put<char> >(ss.getloc());
    npf.put(/*out=*/ss, /*format=*/ss, /*fill=*/' ', value);
    return ss.str();
}

The first parameter to put is the thing where the output is written to.

We can also have code like this and it works:

std::string g(double value) {
    using namespace std;
    stringstream ss;
    typedef char* CharBufOutIt;
    num_put<char, CharBufOutIt> const& npf = use_facet<num_put<char, CharBufOutIt> >(ss.getloc());
    char big_enough_buf[100];
    npf.put(/*out=*/big_enough_buf, /*format=*/ss, /*fill=*/' ', value);
    return big_enough_buf;
}

The second parameter to put() is a stream object that determines the specific formatting to be applied. The second parameter is not modified at all. (Not in my implementation, and not according to what the docs describe this parameter to be for.)

However, the signature of putlooks like this:

iter_type put( iter_type out, std::ios_base& str, char_type fill, long double v ) const;

That is, it is taking the ios_base object by non-const reference, even though it wouild appear it should really take it by const reference.

Am I missing something? Is this just a (historical?) peculiarity in the C++ iostreams spec? Has this ever been discussed by the C++ std committee?

1

There are 1 answers

0
Raxvan On BEST ANSWER

From the Standard (22.4.2.2.2) the implementation of put is at one point as such:

Stage 3:

If str.width() is nonzero and the number of charT’s in the sequence after stage 2 is less than str.width(), then enough fill characters are added to the sequence at the position indicated for padding to bring the length of the sequence to str.width(). str.width(0) is called.`

Also, str.width(0) calls width declared without const (see this link):

streamsize ios_base::width (streamsize wide);