Проблемы вставки CStringW в std :: wostringstream

Я работаю над преобразованием программы MFC из MBCS в Unicode. Я обнаружил, что оператор вставки << с CStringA работает иначе, чем с экземплярами 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());

Я ожидал бы, что это выведет «Hello \ nWorld \ n», но вместо этого будет напечатано «Hello \ n14,5E6, B38 \ n». То есть он печатает адрес данных w_s, а не данных.

Если я отладить в w_oss << w_s, я вижу, что выбирается перегрузка для вставки const void *, а не для вставки const wchar_t *. Это работает правильно для чар версии. Если я явно применяю регистр (LPCTSTR) или (const wchar_t *), он корректно работает для версии wchar_t.

Есть идеи, почему версия wchar_t работает иначе, чем версия char?

4

Решение

Широкая версия символа operator<< является шаблоном и поэтому требует точного совпадения аргумента. Нет пользовательских преобразований, таких как CStringW::operator wchar_t*() неявно выполняется.

ОТОХ void* Версия того же оператора не является шаблоном и успешно использует пользовательский оператор преобразования.

3

Другие решения

Учитывая VS2010 SP1, я обнаружил, что в <ostream> заголовок есть эта перегрузка для std::ostringstream а также const char*:

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

но похоже, что подобной перегрузки для std::wostringstream а также const wchar_t*,

Если вы добавите его в свой исходный код, отправка CStringW с operator<< кажется, работает (мое личное предпочтение: использовать CString::GetString() метод со строковыми потоками и 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's 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

Я думаю, ответ НМ верен. Официальное объяснение довольно туманное, но означает то же самое (MSDN о вводе-выводе с помощью std :: wcout):

Без приведения cs считается пустым *, а wcout печатает
адрес объекта. Это поведение вызвано тонкими взаимодействиями
между выводом аргумента шаблона и разрешением перегрузки, которые
сами по себе правильные и соответствующие стандарту C ++.

2
По вопросам рекламы [email protected]