我想要一个类似于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; }
但是我得到完全相同的输出/编译器错误。
答案 0 :(得分:1)
这是我最终使用的解决方案:
虽然这适用于字符串/字符串,但 <:>>
-
#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
如果我遇到了实际的定义冲突,我可以将重载放在命名空间中,但没有冲突。