将CStringW插入std :: wostringstream时出现问题

时间:2012-10-15 17:09:01

标签: c++ unicode mfc 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&lt;&lt; w_s,我可以看到正在选择插入const void *的重载而不是插入const wchar_t *的重载。它适用于char版本。如果我明确地应用了case(LPCTSTR)或(const wchar_t *),它对wchar_t版本可以正常工作。

为什么wchar_t版本的工作方式与char版本不同?

3 个答案:

答案 0 :(得分:3)

operator<<的宽字符版本是一个模板,因此需要精确的参数匹配。没有隐式执行用户定义的转换,例如CStringW::operator wchar_t*()

OTOH同一运算符的void*版本不是模板,并且很乐意使用用户定义的转换运算符。

答案 1 :(得分:2)

考虑到VS2010 SP1,我发现在<ostream>标题中,std::ostringstreamconst char*存在此重载:

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

std::wostringstreamconst wchar_t*似乎没有类似的重载。

如果您将其添加到源代码中,则CStringWoperator<<一起发送似乎有效(我的个人偏好:对字符串流和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 ++标准。