Problems Inserting CStringW into std :: wostringstream

I am working on converting an MFC program from MBCS to Unicode. I found that the insert statement <<works differently with CStringA than with instances of CStringW.

// char std::ostringstream c_oss; CStringA c_s("Hello"); c_oss << c_s; TRACE("%s\n", c_oss.str().c_str()); // wchar_t std::wostringstream w_oss; CStringW w_s(L"World"); w_oss << w_s; TRACE(L"%s\n", w_oss.str().c_str()); 

I expect this to print "Hello \ nWorld \ n", but instead it will print "Hello \ n14,5E6, B38 \ n". That is, it prints the data address w_s, not the data.

If I debug in w_oss <w_s, I see that the overload to insert const void * is selected, and not to insert const wchar_t *. It works correctly for the char version. If I explicitly apply the register (LPCTSTR) or (const wchar_t *), it works correctly for the wchar_t version.

Any ideas why the wchar_t version works differently than the char version?

+4
source share
3 answers

The wide-format version of operator<< is a template and therefore requires an exact match of arguments. No custom conversion, such as CStringW::operator wchar_t*() , is implicitly executed.

The OTOH version of void* the same operator is not a template and gladly uses a custom conversion operator.

+3
source

Given VS2010 SP1, I found that the <ostream> header has this overload for std::ostringstream and const char* :

 template<class _Traits> inline basic_ostream<char, _Traits>& operator<<( basic_ostream<char, _Traits>& _Ostr, const char *_Val) { // insert NTBS into char stream ... 

but there does not seem to be a similar overload for std::wostringstream and const wchar_t* .

If you add it to the source code, send CStringW using operator<< (my personal preference: use the CString::GetString() method with string streams and operator<< ):

 namespace std { template<class _Traits> inline basic_ostream<wchar_t, _Traits>& operator<<( basic_ostream<wchar_t, _Traits>& _Ostr, const wchar_t *_Val) { ATLTRACE("It me, the new overload!\n"); typedef wchar_t _Elem; // // *** Copy and paste *** the source code from the following overload: // // template<class _Elem, // class _Traits> inline // basic_ostream<_Elem, _Traits>& operator<<( // basic_ostream<_Elem, _Traits>& _Ostr, const _Elem *_Val) // // // NOTE: I don't want to infringe any copyright. // // Moderators please delete the following lines if they // infringe any copyright. // typedef basic_ostream<_Elem, _Traits> _Myos; ios_base::iostate _State = ios_base::goodbit; streamsize _Count = (streamsize)_Traits::length(_Val); // may overflow streamsize _Pad = _Ostr.width() <= 0 || _Ostr.width() <= _Count ? 0 : _Ostr.width() - _Count; const typename _Myos::sentry _Ok(_Ostr); if (!_Ok) _State |= ios_base::badbit; else { // state okay, insert _TRY_IO_BEGIN if ((_Ostr.flags() & ios_base::adjustfield) != ios_base::left) for (; 0 < _Pad; --_Pad) // pad on left if (_Traits::eq_int_type(_Traits::eof(), _Ostr.rdbuf()->sputc(_Ostr.fill()))) { // insertion failed, quit _State |= ios_base::badbit; break; } if (_State == ios_base::goodbit && _Ostr.rdbuf()->sputn(_Val, _Count) != _Count) _State |= ios_base::badbit; if (_State == ios_base::goodbit) for (; 0 < _Pad; --_Pad) // pad on right if (_Traits::eq_int_type(_Traits::eof(), _Ostr.rdbuf()->sputc(_Ostr.fill()))) { // insertion failed, quit _State |= ios_base::badbit; break; } _Ostr.width(0); _CATCH_IO_(_Ostr) } _Ostr.setstate(_State); return (_Ostr); } } // namespace std 
+2
source

I assume nm's answer is correct. The official explanation is rather vague, but means the same thing ( MSDN about IO with std :: wcout ):

Without translation, cs is treated as void *, and wcout prints the address of the object. This behavior is caused by the subtle interaction between subtracting a template argument and resolving overloads, which themselves are correct and conform to the C ++ standard.

+2
source

Source: https://habr.com/ru/post/1439868/


All Articles