2012-10-15 19 views
4

我正在將MFC程序從MBCS轉換爲Unicode。我發現插入運算符< <與CStringA的工作方式相比CStringW實例的工作方式不同。我希望這打印出「Hello \ nWorld \ n」,而是打印出「Hello \ n14,5E6,B38 \ n」。也就是說,它將打印w_s數據的地址而不是數據。問題將CStringW插入std :: wostringstream

如果我調試到w_oss < < w_s,我可以看到插入const void *的重載被選中,而不是插入常量wchar_t *的重載。它的char版本正常工作。如果我明確地應用了大小寫(LPCTSTR)或(const wchar_t *),它對wchar_t版本正常工作。

任何想法爲什麼wchar_t版本的工作方式與char版本不同?

回答

3

寬字符版本的operator<<是一個模板,因此需要精確的參數匹配。沒有用戶定義的轉換,如CStringW::operator wchar_t*()隱式執行。

OTOH void*版本的相同的運算符不是模板,而是很樂意使用用戶定義的轉換運算符。

+0

對於運算符<<的char版本,你寫的東西是否同樣真實? – criddell

+1

通常它也適用於'char *'版本,但我相信在''char *''的MFC深處某處定義了'operator <<'的非標準非模板版本。 –

+0

感謝您的回覆。你寫的所有內容都是正確的,並且通過@Schepurin和Mr.C64添加的信息,我已經能夠讓我的代碼正常工作。我希望我可以選擇所有三個答案爲正確的。 – criddell

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

我想,納米的答案是正確的。官方的解釋是比較飄渺,但意思一樣(MSDN about IO with std::wcout):

沒有投,CS被視爲一個void *和wcout打印對象的 地址。此行爲是由模板參數推導與重載解析之間的微妙交互 引起的,它們本身正確且符合C++標準。

+1

那些_raw_ C風格的轉換(在您引用的MSDN網頁中)並不好;我更喜歡** C++風格的類型轉換**:'CStringW cs(L「...」); std :: wcout << static_cast (cs); << std :: endl;'或_better_只需使用**'CString :: GetString()'方法**:'std :: wcout << cs.GetString()<< std :: endl;'。 –