用于处理宽字符串和非宽字符串的记录器

时间:2015-06-02 15:43:51

标签: c++

我想要一个类似于cout / wcout的单个日志记录函数/宏,但是它可以将std :: string和std :: wstring(以及wchar_t等)作为输入。宽输入在发送到流之前将转换为utf8。理想情况下,使用它看起来像这样:

logger << utf8str << widestr << std::hex << 84 << " blah " << 1.2 << std::endl;

运营商的全局重载&lt;&lt;对我不起作用,因为它与我项目的其他部分发生冲突。

我目前正试图像这样扩展std :: ostringstream:

#include <iostream>
#include <sstream>
#include <string>

#include <locale>
#include <codecvt>
using namespace std;

string WToUTF8(const wstring &wsWide) {
    typedef std::codecvt_utf8<wchar_t> convert_typeX;
    std::wstring_convert<convert_typeX, wchar_t> converterX;
    return converterX.to_bytes(wsWide);
}

struct CLogStream : public virtual std::ostringstream {
    // Allow wstrings
    CLogStream& operator<< (const wstring& ws) { *this << WToUTF8(ws); return *this; }
    // Log wide string literals (e.g. L"widestr") and c-style wide strings as strings instead of hex pointer address
    CLogStream& operator<< (const wchar_t* p_ws) { *this << WToUTF8(p_ws); return *this; }
    // Log wchar_t as a character instead of a number
    CLogStream& operator<< (const wchar_t wc) { *this << WToUTF8(wstring(&wc,1)); return *this; }
};

int main()
{
    string s("narrow ");
    wstring ws(L"_WIDE_");

    CLogStream log;

    // These seem to work how I want them to
    log << "narrow";
    log << L"_WIDE_";
    log << L"_WIDE_" << "narrow";
    log << ws << L"_WIDE_";
    log << s << "narrow";
    log << ws << "narrow";
    log << ws << s;

    // Here I think maybe the compiler uses the ostream << instead of operator<< I defined for CLogStream...
    log << "narrow" << L"_WIDE"; // outputs wide string as a hex value (pointer to the string)
    //log << s << ws;// won't compile - error: no match for 'operator<<' (operand types are 'std::basic_ostream<char>' and 'std::wstring {aka std::basic_string<wchar_t>}')

    cout << log.str();/* output from http://coliru.stacked-crooked.com/:
    narrow_WIDE__WIDE_narrow_WIDE__WIDE_narrow narrow_WIDE_narrow_WIDE_narrow narrow0x4026d4*/
}

这个几乎对我有用,除了当宽输入跟随同一行中的非宽 时,编译器停止使用运算符&lt;&lt;我希望它的定义。任何人都可以解释为什么会这样吗?有没有办法防止它,或者我可以用另一种方法来实现我的目标?

正如所建议的那样,我尝试将流运营商定义为非成员:

    CLogStream& operator<< (CLogStream& strm, const wstring& ws) { strm << WToUTF8(ws); return strm; }
    CLogStream& operator<< (CLogStream& strm, const wchar_t* p_ws) { strm << WToUTF8(p_ws); return strm; }
    CLogStream& operator<< (CLogStream& strm, const wchar_t wc) { strm << WToUTF8(wstring(&wc,1)); return strm; }

但是我得到完全相同的输出/编译器错误。

2 个答案:

答案 0 :(得分:1)

这是我最终使用的解决方案:

虽然这适用于字符串/字符串,但 <:>>

  • 像std :: endl和其他操纵者
  • 之类的东西
  • 数字输入,基于我的输出,我认为被解释为宽字符。

-

#include <iostream>
#include <sstream>
#include <string>

#include <locale>
#include <codecvt>
using namespace std;

string WToUTF8(const wstring &wsWide) {
    typedef std::codecvt_utf8<wchar_t> convert_typeX;
    std::wstring_convert<convert_typeX, wchar_t> converterX;
    return converterX.to_bytes(wsWide);
}

// This part is to avoid globally overloading std::ostringstream's operators,
//  a restriction from elsewhere in my project
struct CLogStream : public virtual std::ostringstream
{   
    CLogStream& operator<< (const wstring& ws) { *this << WToUTF8(ws); return *this; } // Allow wstrings
    CLogStream& operator<< (const wchar_t* p_ws) { *this << WToUTF8(p_ws); return *this; } // c-style wide strings as strings instead of hex pointer address
    CLogStream& operator<< (const wchar_t wc) { *this << WToUTF8(wstring(&wc,1)); return *this; } // wchar_t as a character instead of a number
};

// wrapping the stream prevents the output of CLogStream& operator<< from being interpreted as std::ostringstream
struct CLogger
{
    CLogStream s;
    string str() { return s.str(); }

    template <class T>
    CLogger& operator<<(T&& x) { s << std::forward<T>(x); return *this; }
};

int main()
{
    string s("narrow");
    wstring ws(L"_WIDE_");

    CLogger log;
    log << "narrow" << L"_WIDE" << s << ws; //works
    log << std::hex << 84; //won't compile
    log << std::endl; //won't compile
    log << std::setw(5); //won't compile
    log << "1679.2='" << 1679.2 << "'"; //outputs as character
    log << "534='" << 534 << "'"; //outputs as character

    cout << "log=\n" << log.str() << "done" << endl;
}

答案 1 :(得分:0)

运算符的全局重载&lt;&lt;对我不起作用,因为它与我项目的其他部分发生碰撞。 事实证明这是错误的。在我的重复定义&#34;中,我看起来并不够近。错误 - 真正的问题是我定义了我的&lt;&lt;常见的.h文件中的重载,由多个翻译单元引用(因此每个tu都包含一个新的(重新)定义)。解决方案是内联&#39; .h

中的定义

如果我遇到了实际的定义冲突,我可以将重载放在命名空间中,但没有冲突。