【问题标题】:Problems Inserting a CStringW into a std::wostringstream将 CStringW 插入 std::wostringstream 时出现问题
【发布时间】:2012-10-05 17:17:12
【问题描述】:

我正在将 MFC 程序从 MBCS 转换为 Unicode。我发现插入运算符

// 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

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

【问题讨论】:

    标签: c++ unicode mfc wostringstream


    【解决方案1】:

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

    OTOH 同一运算符的void* 版本不是模板,而是愉快地使用用户定义的转换运算符。

    【讨论】:

    • 对于 char 版本的 operator,您刚才写的所有内容不都是一样的吗?
    • 通常它也适用于char* 版本,但我相信在MFC 深处为char* 定义了operator&lt;&lt; 的非标准非模板版本。
    • 感谢您的回复。你写的一切都是正确的,加上@SChepurin 和 Mr.C64 添加的信息,我已经能够让我的代码正常工作。我希望我能将所有三个答案都选为正确。
    【解决方案2】:

    考虑到 VS2010 SP1,我发现在 &lt;ostream&gt; 标头中,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&lt;&lt; 似乎可以工作(我个人的偏好:使用带有字符串流的CString::GetString() 方法和operator&lt;&lt;):

    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
    

    【讨论】:

      【解决方案3】:

      我猜,nm 的答案是正确的。官方的解释比较模糊,但意思是一样的(MSDN about IO with std::wcout):

      没有强制转换,cs 被视为 void* 并且 wcout 打印 对象的地址。这种行为是由微妙的相互作用引起的 在模板参数推导和重载解析之间 本身正确且符合 C++ 标准。

      【讨论】:

      • 那些 raw C 风格转换(在你引用的 MSDN 网页中)不好;我更喜欢 C++ 风格的演员表,例如:CStringW cs(L"..."); std::wcout &lt;&lt; static_cast&lt;const wchar_t *&gt;(cs); &lt;&lt; std::endl;更好 只需使用 CString::GetString() 方法std::wcout &lt;&lt; cs.GetString() &lt;&lt; std::endl;。跨度>
      猜你喜欢
      • 2023-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多