wchar_t const*
or to wchar_t
not invoked for operator<<
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.
#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
-2- Returns:out
. Constructs a character sequenceseq
. Ifc
has typechar
and the character type of the stream is notchar
, thenseq
consists ofout.widen(c)
; otherwiseseq
consists ofc
. Determines padding forseq
as described in 31.7.6.3.1 [ostream.formatted.reqmts]. Insertsseq
intoout
. Calls.
osout.width(0)out
.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:
-4- Effects: Behaves like a formatted inserter (as described in 31.7.6.3.1 [ostream.formatted.reqmts]) ofs
shall not be a null pointer.out
. Creates a character sequenceseq
ofn
characters starting ats
, each widened usingout.widen()
(27.5.5.3), wheren
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 typeconst charT*
,
and also for the overloadwhere the first argument is of typebasic_ostream<char, traits>&
and the second is of typeconst char*
,where the first argument is of type
basic_ostream<wchar_t, traits>&
and the second is of typeconst wchar_t*
,
std::char_traits<char>::length(s)
for the overload where the first argument is of typebasic_ostream<charT, traits>&
and the second is of typeconst char*
,
traits::length(reinterpret_cast<const char*>(s))
for the other two overloads.Determines padding for
-5- Returns:seq
as described in 31.7.6.3.1 [ostream.formatted.reqmts]. Insertsseq
intoout
. Callsout.width(0)
.out
.