GCC 5.5及以上版本编译嵌套stringstream代码失败问题咨询
GCC 5.5及以上版本编译失败原因分析
问题代码
#include <sstream> namespace util { inline void operator << (std::stringstream& stream, const char* data) { data = data ? data : "(null)"; std::operator<<(stream, data); } } class Record { public: template<typename T> Record& operator<<(const T& data) { using namespace util; m_message << data; return *this; } private: std::stringstream m_message; }; int main() { Record r; std::stringstream m; r << m; // GCC 5.5+编译失败 r << m.str(); // 所有版本正常 return 0; }
根本原因
编译失败的核心是GCC默认C++标准版本变更带来的流对象隐式转换规则变化:
GCC版本的默认标准切换:
GCC 5.1及以后版本默认启用C11标准,而5.1之前的版本默认使用C03标准。流对象隐式转换的差异:
- 在C++03中,
std::ostream(std::stringstream的基类)提供了operator void*() const隐式转换运算符,允许将流对象直接隐式转换为void*。因此当执行m_message << m时,编译器会将const std::stringstream&类型的m隐式转换为const void*,匹配std::ostream::operator<<(const void*)重载,编译通过。 - 在C++11中,该隐式转换被替换为
explicit operator bool() const,禁止了流对象到bool或void*的隐式转换。此时没有任何operator<<重载能匹配const std::stringstream&类型的参数,因此编译失败。
- 在C++03中,
util命名空间的影响:using namespace util;引入的util::operator<<虽然无法匹配const std::stringstream&参数,但会被纳入重载解析的候选列表,导致编译器报错时将其列为候选之一,但这并非编译失败的根本原因——即使移除using namespace util;,在C++11及以后标准下代码依然会编译失败。
验证方法
在GCC 5.5及以上版本中,添加编译选项-std=c++03,代码即可正常编译,这直接验证了是C++标准版本变化导致的问题。
内容的提问来源于stack exchange,提问作者Bilal Ahmed
相关产品推荐
相关产品推荐

