问题描述
我有一个标题,用于帮助使用 MSVC v141 (Visual Studio 2017) 登录应用程序。由于这些日志实用程序很有用,因此我想将其带入我刚刚开始的使用 CMake 和 MinGW/GCC 的项目中。标头本身应该是独立的,它只是执行一些魔术来抽象出公共信息和流目的地,这样我所要做的就是在主循环中调用 InitLogging() 然后调用 LogInfo/LogError/etc,但是当我编译时针对 MinGW(10.3.0 [MSYS2])/GCC(7.5.0 [Ubuntu])
,我收到以下错误:
error: invalid initialization of reference of type ‘const wstringstream& {aka const std::__cxx11::basic_stringstream<wchar_t>&}’ from expression of type ‘std::basic_ostream<wchar_t>’
#define LogInfo(str) { LogMessage(eLogLevel_INFO,std::wstringstream() << LOG_HELPER << str,std::wstringstream() << LOG_HELPER_2); }
/mnt/d/dev/test_logger/src/main.cpp:9:2: note: in expansion of macro ‘LogInfo’
LogInfo(L"Test log");
std::wstring Time2String();
#define LOG_HELPER __FUNCTION__ << L"(): "
#define LOG_HELPER_2 L"[" << Time2String() << "] "
inline void LogMessage(eLogLevel lvl,const std::wstringstream& str,const std::wstringstream& logHelper);//Snipped deFinition
#define LogInfo(str) { LogMessage(eLogLevel_INFO,std::wstringstream() << LOG_HELPER_2); }
如果我只是简单地传递 std::wstreamstring()
而不进行任何插入,或者如果我在调用之外实例化该类型的变量并在调用之外对这些变量执行插入,那么编译器很高兴,尽管它同样如果我尝试对来自类似于当前 #define
的函数调用的变量执行插入,我会很不高兴。
示例:
LogInfo(L"Test log");//compile error
/*******************************************/
std::wstringstream tmpsstream,tmpsstream2;
tmpsstream << LOG_HELPER << L"Test log";
tmpsstream2 << LOG_HELPER_2;
LogMessage(eLogLevel_INFO,tmpsstream,tmpsstream2);//no error
/*******************************************/
LogMessage(eLogLevel_INFO,std::wstringstream(),std::wstringstream());//no error
/*******************************************/
std::wstringstream tmpsstream,tmpsstream2;
LogMessage(eLogLevel_INFO,tmpsstream << LOG_HELPER << L"Test log",tmpsstream2 << LOG_HELPER_2);//compile error
这是 GCC 中的错误还是 MSVC 做了不该做的事情?
解决方法
operator<<
返回对其调用的 std::basic_ostream
对象的引用,即(在本例中)它返回 std::wostream&
,而不是您期望的 std::wstringstream&
。您无法从 const std::wstringstring&
初始化 std::wostream&
,因此会出现错误消息。
由于您的 LogInfo()
宏正在创建一个带有 {}
大括号的新范围,您可以利用您已经发现的解决方案:
如果我......在调用之外实例化该类型的变量并在调用之外对这些变量执行插入,那么编译器很高兴
试试这个:
#define LogInfo(str) { \
std::wstringstream wss,wss2; \
wss << LOG_HELPER << str; \
wss2 << LOG_HELPER_2; \
LogMessage(eLogLevel_INFO,wss,wss2); \
}
否则,如果您不想使用局部变量,那么您将需要显式类型转换 std::wostream&
返回的最终 operator<<
引用,例如:
#define LogInfo(str) { \
LogMessage(eLogLevel_INFO,\
static_cast<std::wstringstream&>(std::wstringstream() << LOG_HELPER << str),\
static_cast<std::wstringstream&>(std::wstringstream() << LOG_HELPER_2) \
); \
}