我正在努力将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&lt;&lt; w_s,我可以看到正在选择插入const void *的重载而不是插入const wchar_t *的重载。它适用于char版本。如果我明确地应用了case(LPCTSTR)或(const wchar_t *),它对wchar_t版本可以正常工作。
为什么wchar_t版本的工作方式与char版本不同?
答案 0 :(得分:3)
operator<<
的宽字符版本是一个模板,因此需要精确的参数匹配。没有隐式执行用户定义的转换,例如CStringW::operator wchar_t*()
。
OTOH同一运算符的void*
版本不是模板,并且很乐意使用用户定义的转换运算符。
答案 1 :(得分:2)
考虑到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 :(得分:2)
我猜,nm的回答是正确的。官方解释相当模糊,但意思相同(MSDN about IO with std::wcout):
没有演员表,cs被视为空格*并且wcout打印出来 对象的地址。此行为是由细微的交互引起的 模板参数推导和重载解析之间的关系 本身正确且符合C ++标准。