This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++14 status.
2011. Unexpected output required of stringsSection: 27.4.4.4 [string.io] Status: C++14 Submitter: James Kanze Opened: 2010-07-23 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [string.io].
View all issues with C++14 status.
Discussion:
What should the following code output?
#include <string> #include <iostream> #include <iomanip> int main() { std::string test("0X1Y2Z"); std::cout.fill('*'); std::cout.setf(std::ios::internal, std::ios::adjustfield); std::cout << std::setw(8) << test << std::endl; }
I would expect "**0X1Y2Z
", and this is what the compilers I have access to (VC++, g++ and Sun CC) do. But according to the standard, it should be "0X**1Y2Z
":
27.4.4.4 [string.io]/5:
template<class charT, class traits, class Allocator> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string<charT,traits,Allocator>& str);Effects: Behaves as a formatted output function (31.7.6.3.1 [ostream.formatted.reqmts]). After constructing a
sentry
object, if this object returnstrue
when converted to a value of typebool
, determines padding as described in 28.3.4.3.3.3 [facet.num.put.virtuals], then inserts the resulting sequence of characters seq as if by callingos.rdbuf()->sputn(seq, n)
, wheren
is the larger ofos.width()
andstr.size()
; then callsos.width(0)
.
28.3.4.3.3.3 [facet.num.put.virtuals]/5:
[…]
Stage 3: A local variable is initialized as
fmtflags adjustfield= (flags & (ios_base::adjustfield));The location of any padding is determined according to Table 88.
If
Table 88 — Fill padding State Locationstr.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.adjustfield == ios_base::left
pad afteradjustfield == ios_base::right
pad beforeadjustfield == internal
and a sign occurs in the representation pad after the signadjustfield == internal
and representation after stage 1 began with 0x or 0X pad after x or X otherwise pad before
Although it's not 100% clear what "the sequence after stage 2" should mean here, when there is no stage 2, the only reasonable assumption is that it is the contents of the string being output. In the above code, the string being output is "0X1Y2Z
", which starts with "0X
", so the padding should be inserted "after x or X", and not before the string. I believe that this is a defect in the standard, and not in the three compilers I tried.
[ 2010 Batavia (post meeting session) ]
Consensus that all known implementations are consistent, and disagree with the standard. Preference is to fix the standard before implementations start trying to conform to the current spec, as the current implementations have the preferred form. Howard volunteered to drught for Madrid, move to Open.
[2011-03-24 Madrid meeting]
Daniel Krügler volunteered to provide wording, interacting with Dietmar and Bill.
[2011-06-24 Daniel comments and provides wording]
The same problem applies to the output provided by const char*
and similar character sequences as of 31.7.6.3.4 [ostream.inserters.character] p. 5. and even for single character output (!) as described in 31.7.6.3.4 [ostream.inserters.character] p. 1, just consider the character value '-' where '-' is the sign character. In this case Table 91 — "Fill padding" requires to pad after the sign, i.e. the output for the program
#include <iostream> #include <iomanip> int main() { char c = '-'; std::cout.fill('*'); std::cout.setf(std::ios::internal, std::ios::adjustfield); std::cout << std::setw(2) << c << std::endl; }
According to the current wording this program should output "-*
", but all tested implementations output "*-
" instead.
money_put
functions.
[ 2011 Bloomington ]
Move to Review, the resolution seems correct but it would be nice if some factoring of the common words were proposed.
[2012, Kona]
Moved to Tentatively Ready by the post-Kona issues processing subgroup.
While better factoring of the common words is desirable, it is also editorial and should not hold up the progress of this issue. As the edits impact two distinct clauses, it is not entirely clear what a better factoring should look like.
[2012, Portland: applied to WP]
Proposed resolution:
The new wording refers to the FDIS numbering.
Change 27.4.4.4 [string.io]/5 as indicated:
template<class charT, class traits, class Allocator> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string<charT,traits,Allocator>& str);-5- Effects: Behaves as a formatted output function ([ostream.formatted.reqmts]). After constructing a sentry object, if this object returns
true
when converted to a value of typebool
, determines padding as described in [facet.num.put.virtuals], follows: AcharT
character sequence is produced, initially consisting of the elements defined by the range[str.begin(), str.end())
. Ifstr.size()
is less thanos.width()
, then enough copies ofos.fill()
are added to this sequence as necessary to pad to a width ofos.width()
characters. If(os.flags() & ios_base::adjustfield) == ios_base::left
istrue
, the fill characters are placed after the character sequence; otherwise, they are placed before the character sequence. T then inserts the resulting sequence of charactersseq
as if by callingos.rdbuf()->sputn(seq, n)
, wheren
is the larger ofos.width()
andstr.size()
; then callsos.width(0)
.
Change 31.7.6.3.4 [ostream.inserters.character]/1 as indicated (An additional editorial fix is suggested for the first prototype declaration):
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, charT c}); template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, char c); // specialization template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, char c); // signed and unsigned template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, signed char c); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, unsigned char c);-1- Effects: Behaves like a formatted inserter (as described in [ostream.formatted.reqmts]) of
out
. After a sentry object is constructed it inserts characters. In casec
has typechar
and the character type of the stream is notchar
, then the character to be inserted isout.widen(c)
; otherwise the character isc
. Padding is determined as described in [facet.num.put.virtuals] follows: A character sequence is produced, initially consisting of the insertion character. Ifout.width()
is greater than one, then enough copies ofout.fill()
are added to this sequence as necessary to pad to a width ofout.width()
characters. If(out.flags() & ios_base::adjustfield) == ios_base::left
istrue
, the fill characters are placed after the insertion character; otherwise, they are placed before the insertion character.width(0)
is called. The insertion character and any required padding are inserted intoout
; then callsos.width(0)
.
Change 31.7.6.3.4 [ostream.inserters.character]/5 as indicated:
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, const charT* s); template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>& out, const char* s); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const char* s); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const signed char* s); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const unsigned char* s);[…]
-5- Padding is determined as described in [facet.num.put.virtuals]. Then
characters starting ats
are widened usingout.widen
([basic.ios.members]) follows: A character sequence is produced, initially consisting of the elements defined by then
characters starting ats
widened usingout.widen
([basic.ios.members]). Ifn
is less thanout.width()
, then enough copies ofout.fill()
are added to this sequence as necessary to pad to a width ofout.width()
characters. If(out.flags() & ios_base::adjustfield) == ios_base::left
istrue
, the fill characters are placed after the character sequence; otherwise, they are placed before the character sequence. The widened characters and any required padding are inserted intoout
. Callswidth(0)
.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4