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.

### 2342. User conversion to `wchar_t const*` or to `wchar_t` not invoked for `operator<<`

Section: 29.7.5.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.

1. Modify 29.7.5.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*);
   >     […]
   >     }

2. Modify 29.7.5.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 (29.7.5.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 29.7.5.3.1 [ostream.formatted.reqmts]. Inserts `seq` into `out`. Calls `osout.width(0)`.

   > > -2- Returns: `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: `s` shall not be a null pointer.

   > > -4- Effects: Behaves like a formatted inserter (as described in 29.7.5.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 overload where 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 29.7.5.3.1 [ostream.formatted.reqmts]. Inserts `seq` into `out`. Calls `out.width(0)`.

   > > -5- Returns: `out`.