This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
Section: 31.7.6.2 [ostream] Status: New Submitter: Alf P. Steinbach Opened: 2013-10-29 Last modified: 2016-01-28
Priority: 4
View all other issues in [ostream].
View all issues with New status.
Discussion:
For wide streams argument types wchar_t const* and wchar_t are supported only as template parameters. User defined conversions are not considered for template parameter matching. Hence inappropriate overloads of operator<< are selected when an implicit conversion is required for the argument, which is inconsistent with the behavior for char const* and char, is unexpected, and is a useless result.
Demonstration:#include <iostream> struct Byte_string { operator char const*() const { return "Hurray, it works!"; } }; struct Wide_string { operator wchar_t const*() const { return L"Hurray, it works!"; } }; struct Byte_ch { operator char() const { return 'X'; } }; struct Wide_ch { operator wchar_t() const { return L'X'; } }; auto main() -> int { using namespace std; wcout << "'X' as char value : " << Byte_ch() << endl; wcout << "'X' as wchar_t value: " << Wide_ch() << endl; wcout << "Byte string pointer : " << Byte_string() << endl; wcout << "Wide string pointer : " << Wide_string() << endl; }
Example output:
'X' as char value : X 'X' as wchar_t value: 88 Byte string pointer : Hurray, it works! Wide string pointer : 000803C8
Proposed resolution:
This wording is relative to N3797.
Modify 31.7.6.2 [ostream], class template basic_ostream synopsis, as indicated:
namespace std { […] // 27.7.3.6.4 character inserters template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, charT); template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, char); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, char); template<class traits> basic_ostream<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>&, wchar_t); […] template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*); template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const char*); template<class traits> basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>&, const char*); template<class traits> basic_ostream<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>&, const wchar_t*); […] }
Modify 31.7.6.3.4 [ostream.inserters.character] as indicated: [Drafting note: The replacement of os by out in p1 and the insertion of "out." in p4 just fix two obvious typos — end drafting note]
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); template<class traits> basic_ostream<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>& out, wchar_t 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 as a formatted output function (31.7.6.3.1 [ostream.formatted.reqmts]) of out. Constructs a character sequence seq. If c has type char and the character type of the stream is not char, then seq consists of out.widen(c); otherwise seq consists of c. Determines padding for seq as described in 31.7.6.3.1 [ostream.formatted.reqmts]. Inserts seq into out. Calls
-2- Returns: out.osout.width(0).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<wchar_t,traits>& operator<<(basic_ostream<wchar_t,traits>& out, const wchar_t* 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);-3- Requires: s shall not be a null pointer.
-4- Effects: Behaves like a formatted inserter (as described in 31.7.6.3.1 [ostream.formatted.reqmts]) of out. Creates a character sequence seq of n characters starting at s, each widened using out.widen() (27.5.5.3), where n is the number that would be computed as if by:
traits::length(s) for the following overloads:
where the first argument is of type basic_ostream<charT, traits>& and the second is of type const charT*,
and also for the overloadwhere the first argument is of type basic_ostream<char, traits>& and the second is of type const char*,where the first argument is of type basic_ostream<wchar_t, traits>& and the second is of type const wchar_t*,
std::char_traits<char>::length(s) for the overload where the first argument is of type basic_ostream<charT, traits>& and the second is of type const char*,
traits::length(reinterpret_cast<const char*>(s)) for the other two overloads.
Determines padding for seq as described in 31.7.6.3.1 [ostream.formatted.reqmts]. Inserts seq into out. Calls out.width(0).
-5- Returns: out.