Project: ISO C++ Date: 1998-8-13 Doc. No.: J16/98-0017 = WG21/N1160 Author: Nathan Myers locale combine(const locale& other) const; -------------------------------------------------------------------------- 2. 22.1.1.3 [lib.locale.members] locale::name requirement inconsistent locale::name() is described as returning a string that can be passed to a locale constructor, but there is no matching constructor. Proposed Resolution: In 22.1.1.3 [lib.locale.members], paragraph 5, replace "locale(name())" with "locale(name().c_str())". -------------------------------------------------------------------------- 3. 22.2.1.4, [lib.locale.ctype.byname.special] bad ctype_byname decl The new virtual members ctype_byname::do_widen and do_narrow did not get edited in properly. Instead, the member do_widen appears four times, with wrong argument lists. Proposed Resolution: The correct declarations for the overloaded members do_narrow and do_widen should be copied from 22.2.1.3, [lib.facet.ctype.special]. -------------------------------------------------------------------------- 4. 22.2.2.1.2 [lib.facet.num.get.virtuals] bad bool parsing This section describes the process of parsing a text boolean value from the input stream. It does not say it recognizes either of the sequences "true" or "false" and returns the corresponding bool value. Instead, it says it recognizes only one of those sequences, and chooses which according to the received value of a reference argument intended for returning the result, and reports an error if the other sequence is found. (!) Furthermore, it claims to get the names from the ctype<> facet rather than the numpunct<> facet, and it examines the "boolalpha" flag wrongly. Finally, it doesn't define the value "loc". In other words, the description is full of errors, and if the obvious errors are corrected, the result is unusable. I believe the correct algorithm is "as if": // in, err, val, and str are arguments. err = 0; const numpunct& np = use_facet >(str.getloc()); const string_type t = np.truename(); const string_type f = np.falsename(); bool tm = true; bool fm = true; size_t pos = 0; while (tm && pos != t.size() || fm && pos != f.size()) { if (in == end) { err = str.eofbit; } bool matched = false; if (tm && pos < t.size()) { if (!err && t[pos] == *in) matched = true; else tm = false; } if (fm && pos < f.size()) { if (!err && f[pos] == *in) matched = true; else fm = false; } if (matched) { ++in; ++pos; } if (pos > t.size()) tm = false; if (pos > f.size()) fm = false; if (!tm && !fm) { err |= str.failbit; return in; } } val = tm; return in; Notice this works when the candidate strings are both empty, and when one is a substring of the other. The proposed text below captures the logic of the code above. Proposed resolution: In 22.2.2.1.2 [lib.facet.num.get.virtuals], replace paragraphs 15 and 16 as follows: Otherwise target sequences are determined "as if" by calling the members _falsename()_ and _truename()_ of the facet obtained by _use_facet< numpunct >(str.getloc())_. Successive characters in the range _[in,end)_ (see [lib.sequence.reqmts]) are obtained and matched against corresponding positions in the target sequences only as necessary to identify a unique match. If a target sequence is uniquely matched, _val_ is set to the corresponding value; or if the targets are identical and matched, _val_ is set to _true_. The _in_ iterator is always left pointing one position beyond the last character successfully matched. If _val_ is set, then err is set to _str.goodbit_; or to _str.eofbit_ if, when seeking another character to match, it is found that _(in==end)_. If _val_ is not set, then _err_ is set to _str.failbit_; or to _(str.failbit|str.eofbit)_ if the reason for the failure was that _(in==end)_. [Example: for targets _true_:"a" and _false_:"abb", the input sequence "a" yields _val==true_ and _err==str.eofbit_; the input sequence "abc" yields _err=str.failbit_, with _in_ ending at the 'c' element. For targets _true_:"1" and _false_:"0", the input sequence "1" yields _val==true_ and _err=str.goodbit_. For empty targets (""), any input sequence yields _val==true_ and _err==str.goodbit_. --end example] Also: in the first line of paragraph 14, change "&&" to "&". -------------------------------------------------------------------------- 5. 22.2.2.1.1 [lib.facet.num.get.members] get(...bool&) omitted In the list of num_get<> non-virtual members on page 22-23, the member that parses bool values was omitted from the list of definitions of non-virtual members, though it is listed in the class definition and the corresponding virtual is listed everywhere appropriate. Proposed Resolution: Add at the beginning of 22.2.2.1.1 [lib.facet.num.get.members] another get member for bool&, copied from the entry in 22.2.2.1 [lib.locale.num.get]. -------------------------------------------------------------------------- 6. 22.2.1.5.2 [lib.locale.codecvt.virtuals] "noconv" definition too vague. In the definitions of codecvt<>::do_out and do_in, they are specified to return noconv if "no conversion is needed". This definition is too vague, and does not say normatively what is done with the buffers. Proposed Resolution: Change the entry for noconv in the table under paragraph 4 in section 22.2.1.5.2 [lib.locale.codecvt.virtuals] to read: noconv: input sequence is identical to converted sequence. and change the Note in paragraph 2 to normative text as follows: If returns _noconv_, the converted sequence is identical to the input sequence _[from,from_next)_._to_next_ is set equal to _to_, and the value of _state_ is unchanged. -------------------------------------------------------------------------- 7. 22.2.3.1.2 [lib.facet.numpunct.virtuals] thousands_sep returns wrong type The synopsis for numpunct<>::do_thousands_sep, and the definition of numpunct<>::thousands_sep which calls it, specify that it returns a value of type char_type. Here it is erroneously described as returning a "string_type". Proposed resolution: In 22.2.3.1.2 [lib.facet.numpunct.virtuals], above paragraph 2, change "string_type" to "char_type". -------------------------------------------------------------------------- 8. 22.1.1.1.1 [lib.locale.category] codecvt_byname<> instantiations In the second table in the section, captioned "Required instantiations", the instantiations for codecvt_byname<> have been omitted. These are necessary to allow users to construct a locale by name from facets. Proposed resolution: Add in 22.1.1.1.1 [lib.locale.category] to the table captioned "Required instantiations", in the category "ctype" the lines codecvt_byname, codecvt_byname -------------------------------------------------------------------------- 9. 27.8.1.7 [lib.ifstream.members] member open vs. flags The description of basic_istream<>::open leaves unanswered questions about how it responds to or changes flags in the error status for the stream. A strict reading indicates that it ignores the bits and does not change them, which confuses users who do not expect eofbit and failbit to remain set after a successful open. There are three reasonable resolutions: 1) status quo 2) fail if fail(), ignore eofbit 3) clear failbit and eofbit on call to open(). Proposed resolution: In 27.8.1.7 [lib.ifstream.members], _and_ in 27.8.1.10 [lib.ofstream.members], under open(), one of A. no change B. Prepend to Effects: "If fail(), returns. Otherwise"... C. Prepend to Effects: "Call clear(); then," ... -------------------------------------------------------------------------- 10. 27.8.1.10 [lib.ofstream.members] member open vs. flags (same as issue 9, respective.) -------------------------------------------------------------------------- 11. 22.2.2.1.2 [lib.facet.num.get.virtuals] num_get overflow result The current description of numeric input does not account for the possibility of overflow. This is an implicit result of changing the description to rely on the definition of scanf() (which fails to report overflow), and conflicts with the documented behavior of traditional and current implementations. Users expect, when reading a character sequence that results in a value unrepresentable in the specified type, to have an error reported. The standard as written does not permit this. Proposed Resolution: In 22.2.2.1.2 [lib.facet.num.get.virtuals], paragraph 11, second bullet item, change The sequence of chars accumulated in stage 2 would have caused scanf to report an input failure. to The sequence of chars accumulated in stage 2 would have caused scanf to report an input failure, or the value of the sequence cannot be represented in the type of _val_. -------------------------------------------------------------------------- 12. 22.2.1.5.2 [lib.locale.codecvt.virtuals] "do_convert" doesn't exist The description of codecvt<>::do_out and do_in mentions a symbol "do_convert" which is not defined in the standard. This is a leftover from an edit, and should be "do_in and do_out". Proposed Resolution: In 22.2.1.5 [lib.locale.codecvt], paragraph 3, change "do_convert" to "do_in or do_out". Also, In 22.2.1.5.2 [lib.locale.codecvt.virtuals], change "do_convert()" to "do_in or do_out". -------------------------------------------------------------------------- 13. 21.3.7.9 [lib.string.io] string op>> uses width() value wrong. In the description of operator>> applied to strings, the standard says that uses the smaller of os.width() and str.size(), to pad "as described in stage 3" elsewhere; but this is inconsistent, as this allows no possibility of space for padding. Proposed Resolution: In 21.3.7.9 [lib.string.io], paragraph 3, change the word "smaller" to "larger". -------------------------------------------------------------------------- 14. 27.6.1.1.2 [lib.istream::sentry] Bad sentry example In paragraph 6, the code in the example: template > basic_istream::sentry( basic_istream& is, bool noskipws = false) { ... int_type c; typedef ctype ctype_type; const ctype_type& ctype = use_facet(is.getloc()); while ((c = is.rdbuf()->snextc()) != traits::eof()) { if (ctype.is(ctype.space,c)==0) { is.rdbuf()->sputbackc (c); break; } } ... } fails to demonstrate correct use of the facilities described. In particular, it fails to use traits operators, and specifies incorrect semantics. (E.g. it specifies skipping over the first character in the sequence without examining it.) Proposed Resolution: Replace the example with better code, as follows: template > basic_istream::sentry( basic_istream& is, bool noskipws = false) { ... typedef ctype ctype_type; const ctype_type& ct = use_facet(is.getloc()); for (int_type c = is.rdbuf()->sgetc(); !traits::eq_int_type(c,traits::eof()) && ct.is(ctype.space,c); c = is.rdbuf()->snextc()) {} ... } -------------------------------------------------------------------------- 15. 21.3.5.5 [lib.string::erase] string::erase(range) yields wrong iterator The string::erase(iterator first, iterator last) is specified to return an element one place beyond the next element after the last one erased. E.g. for the string "abcde", erasing the range ['b'..'d') would yield an iterator for element 'e', while 'd' has not been erased. Proposed Resolution: In 21.3.5.5 [lib.string::erase], paragraph 10, change: Returns: an iterator which points to the element immediately following _last_ prior to the element being erased. to read Returns: an iterator which points to the element pointed to by _last_ prior to the other elements being erased. -------------------------------------------------------------------------- 16. 22.2.1.3.2 [lib.facet.ctype.char.members] ctypeis ambiguous The description of the vector form of ctype::is can be interpreted to mean something very different from what was intended. Paragraph 4 says Effects: The second form, for all *p in the range [low, high), assigns vec[p-low] to table()[(unsigned char)*p]. This is intended to copy the value indexed from table()[] into the place identified in vec[]. Proposed Resolution: Change 22.2.1.3.2 [lib.facet.ctype.char.members], paragraph 4, to read Effects: The second form, for all *p in the range [low, high), assigns into vec[p-low] the value table()[(unsigned char)*p]. -------------------------------------------------------------------------- 17. 27.3.1 [lib.narrow.stream.objects] ios_base::init doesn't exist Sections 27.3.1 and 27.3.2 [lib.wide.stream.objects] mention a function ios_base::init, which is not defined. Probably it means basic_ios<>::init, defined in 27.4.4.1 [lib.basic.ios.cons], paragraph 3. Proposed Resolution: In 27.3.1 [lib.narrow.stream.objects] paragraph 2, change ios_base::init to basic_ios::init Also, make a similar change in 27.3.2 [lib.wide.stream.objects] except it should read basic_ios::init -------------------------------------------------------------------------- 18. 22.1.1.1.1 [lib.locale.category] wrong header for LC_* Paragraph 2 implies that the C macros LC_CTYPE etc. are defined in , where they are in fact defined elsewhere to appear in . Proposed Resolution: In 22.1.1.1.1 [lib.locale.category], paragraph 2, change "" to read "". -------------------------------------------------------------------------- 19. 22.1.1 [lib.locale] immutable locale values Paragraph 6, says "An instance of _locale_ is *immutable*; once a facet reference is obtained from it, ...". This has caused some confusion, because locale variables are manifestly assignable. Proposed Resolution: In 22.1.1 [lib.locale] paragraph 6, replace the text "An instance of _locale_ is *immutable*;" with "A _locale_ value is *immutable*;" -------------------------------------------------------------------------- 20. 27.5.2.4.4 [lib.streambuf.virt.pback] pbackfail description inconsistent The description of the required state before calling virtual member basic_streambuf<>::pbackfail requirements is inconsistent with the conditions described in 27.5.2.2.4 [lib.streambuf.pub.pback] where member sputbackc calls it. Specifically, the latter says it calls pbackfail if: traits::eq(c,gptr()[-1]) is false where pbackfail claims to require: traits::eq(*gptr(),traits::to_char_type(c)) returns false It appears that the pbackfail description is wrong. Proposed Resolution: In 27.5.2.4.4 [lib.streambuf.virt.pback], paragraph 1, change "*gptr()" to read instead "gptr()[-1]". -------------------------------------------------------------------------- 21. 22.2.1.5.2 [lib.locale.codecvt.virtuals] codecvt<> mentions from_type In the table defining the results from do_out and do_in, the specification for the result _error_ says encountered a from_type character it could not convert but from_type is not defined. This clearly is intended to be an externT for do_in, or an internT for do_out. Proposed Resolution: In 22.2.1.5.2 [lib.locale.codecvt.virtuals], paragraph 4, replace the definition in the table for the case of _error_ with enountered a character in [from,from_end) that it could not convert. -------------------------------------------------------------------------- 22. 22.2.2.2.2 [lib.facet.num.get.virtuals] true/falsename() not in ctype<>. In paragraph 19, Effects:, members truename() and falsename are used from facet ctype, but it has no such members. Note that this is also a problem in 22.2.2.1.2, addressed in (4). Proposed Resolution In 22.2.2.2.2 [lib.facet.num.put.virtuals], paragraph 19, in the Effects: clause for member put(...., bool), replace the initialization of the string_type value s as follows: const numpunct& np = use_facet >(loc); string_type s = val ? np.truename() : np.falsename(); -------------------------------------------------------------------------- 23. 27.4 [lib.iostreams.base] No manipulator unitbuf in synopsis In 27.4.5.1, [lib.fmtflags.manip], we have a definition for a manipulator named "unitbuf". Unlike other manipulators, it's not listed in sysopsis. Similarly for "nounitbuf". Proposed Resolution: Add to the synopsis for in 27.4 [lib.iostreams.base], after the entry for "nouppercase", the prototypes: ios_base& unitbuf(ios_base& str); ios_base& nounitbuf(ios_base& str); -------------------------------------------------------------------------- 24. 27.4.2.5 [lib.ios.base.storage] iword & pword storage lifetime omitted In the definitions for ios_base::iword and pword, the lifetime of the storage is specified badly, so that an implementation which only keeps the last value stored appears to conform. In particular, it says: The reference returned may become invalid after another call to the object's iword member with a different index ... This is not idle speculation; at least one implementation was done this way. Proposed Resolution: Add in 27.4.2.5 [lib.ios.base.storage], in both paragraph 2 and also in paragraph 4, replace the sentence: The reference returned may become invalid after another call to the object's iword [pword] member with a different index, after a call to its copyfmt member, or when the object is destroyed. with: The reference returned is invalid after any other operations on the object. However, the value of the storage referred to is retained, so that until the next call to copyfmt, calling iword [pword] with the same index yields another reference to the same value. substituting "iword" or "pword" as appropriate. 25. 22.1.1 [lib.locale] leftover "global" reference In the overview of locale semantics, paragraph 4, is the sentence If Facet is not present in a locale (or, failing that, in the global locale), it throws the standard exception bad_cast. This is not supported by the definition of use_facet<>, and represents semantics from an old draft. Proposed Resolution: In 22.1.1 [lib.locale], paragraph 4, delete the parenthesized expression (or, failing that, in the global locale) -------------------------------------------------------------------------- 26. 22.1.2 [lib.locale.global.templates] Facet definition incomplete. Esa Pulkkinen has noticed that the definition of "facet" is incomplete. In particular, a class derived from another facet, but which does not define a member _id_, cannot safely serve as the argument _F_ to use_facet(loc), because there is no guarantee that a reference to the facet instance stored in _loc_ is safely convertible to _F_. Proposed Resolution: In the definition of std::use_facet<>(), replace the text in paragraph 1 which reads: Get a reference to a facet of a locale. with: Requires: _Facet_ is a facet class whose definition contains (not inherits) the public static member id as defined in (22.1.1.1.2, [lib.locale.facet]). -------------------------------------------------------------------------- 27. 24.5.3.4 [lib.istreambuf.iterator::op++] sbufiter ++ definition garbled Following the definition of istreambuf_iterator<>::operator++(int) in paragraph 3, the standard contains three lines of garbage text left over from a previous edit. istreambuf_iterator tmp = *this; sbuf_->sbumpc(); return(tmp); Proposed Resolution: In 24.5.3.4 [lib.istreambuf.iterator::op++], delete the three lines of code at the end of paragraph 3. -------------------------------------------------------------------------- 28. 22.2.8 [lib.facets.examples] meaningless normative paragraph in examples Paragraph 3 of the locale examples is a description of part of an implementation technique that has lost its referent, and doesn't mean anything. Proposed Resolution: Delete 22.2.8 [lib.facets.examples] paragraph 3, or (at the editor's option) replace it with a place-holder to keep the paragraph numbering the same. -------------------------------------------------------------------------- 29. 27.4.2 [lib.ios.base] ios_base needs clear(), exceptions() The description of ios_base::iword() and pword() in 27.4.2.4 [lib.ios.members.static], say that if they fail, they "set badbit, which may throw an exception". However, ios_base offers no interface to set or to test badbit; those interfaces are defined in basic_ios<>. Proposed Resolution: One of: A. Move the definitions of basic_ios<> members clear, setstate, good, eof, fail, bad, and exceptions from basic_ios<> to ios_base. In particular, move them from the basic_ios<> synopsis 27.4.4 [lib.ios] and the definitions 27.4.4.3 [lib.iostate.flags] to the ios_base synopsis 27.4.2 [lib.ios.base] and definitions 27.4.2.1.2 [lib.ios::fmtflags] sections, respectively. B. Change the description in 27.4.2.4 [lib.ios.members.static] in paragraph 2 and also in paragraph 4 as follows. Replace If the function fails it sets badbit, which may throw an exception. with If the function fails, and *this is a subobject of a basic_ios<> object or subobject, the failure may be detected by -------------------------------------------------------------------------- 30. 21.3 [lib.basic.string] string ctors specify wrong default allocator The basic_string<> copy constructor: basic_string(const basic_string& str, size_type pos = 0, size_type n = npos, const Allocator& a = Allocator()); specifies an Allocator argument default value that is counter-intuitive. The natural choice for a the allocator to copy from is str.get_allocator(). Though this cannot be expressed in default-argument notation, overloading suffices. Alternatively, the other containers in Clause 23 (deque, list, vector) do not have this form of constructor, so it is inconsistent, and an evident source of confusion, for basic_string<> to have it, so it might better be removed. Proposed Resolution: One of: A. In 21.3 [lib.basic.string], replace the declaration of the copy constructor as follows: basic_string(const basic_string& str, size_type pos = 0, size_type n = npos); basic_string(const basic_string& str, size_type pos, size_type n, const Allocator& a); In 21.3.1 [lib.string.cons], replace the copy constructor declaration as above. Add to paragraph 5, Effects: When no _Allocator_ argument is provided, the string is constructed using the value _str.get_allocator()_. B. In 21.3 [lib.basic.string], and also in 21.3.1 [lib.string.cons], replace the declaration of the copy constructor as follows: basic_string(const basic_string& str, size_type pos = 0, size_type n = npos); -------------------------------------------------------------------------- 31. 23.2.2 [lib.list] list operations should not invalidate list iterators A resolution was passed to add a statement that list iterators are not invalidated by various list<> operations which do not affect the specific nodes referred to. That statement failed to be edited into the final draft. The correct semantics of list<> depend on such a statement; we should restore it. Proposed Resolution: (none yet) -------------------------------------------------------------------------- 32. 27 [lib.input.output] iostreams use operator== on int_type values Many of the specifications for iostreams specify that character values or their int_type equivalents are compared using operators == or !=, though in other places traits::eq() or traits::eq_int_type is specified to be used throughout. This is an inconsistency; we should change uses of == and != to use the traits members instead. Proposed Resolution: (not ready yet) -------------------------------------------------------------------------- 33. 27.7 [lib.string.streams] stringstream in/out pointer positions There have been reports about inconsistencies in the description of stringstream "file positions". -------------------------------------------------------------------------- 34. 22.2.2.1.2 [lib.facet.num.get.virtuals] op<< exit conditions inconsistent The condition of the iterator (file position) and the states of the failbit and eofbit flags for the various input parsing functions in facets num_get, time_get, money_get, and istream operators << and member get have been noted to be inconsistent. -------------------------------------------------------------------------- 35. 21.1.1 [lib.char.traits.require] char_traits<>::lt and eq vs compare I have a note that suggests the char_traits<> members lt and eq are inconsistent with the definition of member compare. Proposed Resolution: (none) -------------------------------------------------------------------------- 36. 22.2.5.1 [lib.locale.time.get] do_get_monthname synopsis missing argument The locale facet member time_get<>::do_get_monthname is described in 22.2.5.1.2 [lib.locale.time.get.virtuals] with five arguments, consistent with do_get_weekday and with its specified use by member get_monthname. However, in the synopsis, it is specified instead with four arguments. The missing argument is the "end" iterator value. This could reasonably be considered a purely-editorial inconsistency. Proposed Resolution: In 22.2.5.1 [lib.locale.time.get], replace the declaration of member do_monthname as follows: virtual iter_type do_get_monthname(iter_type s, iter_type end, ios_base&, ios_base::iostate& err, tm* t) const;