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.
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. Ifchas typecharand the character type of the stream is notchar, thenseqconsists ofout.widen(c); otherwiseseqconsists ofc. Determines padding forseqas described in 31.7.6.3.1 [ostream.formatted.reqmts]. Insertsseqintoout. 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]) ofsshall not be a null pointer.out. Creates a character sequenceseqofncharacters starting ats, each widened usingout.widen()(27.5.5.3), wherenis 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:seqas described in 31.7.6.3.1 [ostream.formatted.reqmts]. Insertsseqintoout. Callsout.width(0).out.