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 put
looks 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?
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 ofcharT’s
in the sequence after stage 2 is less thanstr.width()
, then enough fill characters are added to the sequence at the position indicated for padding to bring the length of the sequence tostr.width()
.str.width(0)
is called.`
Also, str.width(0)
calls width
declared without const
(see this link):
streamsize ios_base::width (streamsize wide);