提问人:Bilal Ahmed 提问时间:5/30/2023 最后编辑:Bilal Ahmed 更新时间:5/31/2023 访问量:69
在 stringstream 中流式传输字符串流 代码针对 GCC 编译,直到 V5.5 版本,但以下版本不编译
Streaming a stringstream within a stringstream Code compiles for GCC until V5.5 but not the following versions
问:
我有以下C++代码可以成功编译 gcc < v5.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;
// std::cout << data << std::endl;
return *this;
}
private:
std::stringstream m_message;
};
int main()
{
Record r;
std::stringstream m;
r << m; //Error after gcc5.5
r << m.str(); //Ok in both
return 0;
}
看起来将字符串流传递给字符串流不再有效。我不知道为什么。
下面是一个比较链接:https://godbolt.org/z/novWE3so8
答:
1赞
Turtlefight
5/31/2023
#1
这不取决于 gcc 版本,而是取决于您正在编译的 C++ 标准版本。
在编译 C++03 时,您的示例在最新的 gcc 版本上没有问题:godbolt
这完全编译的原因是 C++11 之前没有数据类型。
因此,检查流是否有效(例如)被要求只返回一些未指定的类似布尔的类型:bool
if(stream) { /*...*/ }
operator /* unspecified-boolean-type */() const; // (until C++11) explicit operator bool() const; // (since C++11)
请注意,转换在 C++11 之前也是隐式的,因为显式转换函数是在 C++11 中添加的。
libstdc++ 恰好定义了转换运算符,如下所示:github
///@{
/**
* @brief The quick-and-easy status check.
*
* This allows you to write constructs such as
* <code>if (!a_stream) ...</code> and <code>while (a_stream) ...</code>
*/
#if __cplusplus >= 201103L
explicit operator bool() const { return !this->fail(); }
#else
operator void*() const { return this->fail() ? 0 : const_cast<basic_ios*>(this); }
#endif
请注意,这允许从任何流到 .void*
这很不幸,因为它为输出指针提供了重载:
cppreferencestd::basic_ostream
basic_ostream& operator<<( const void* value ); // (8)
因此,在您的示例中实际发生的情况是,流被隐式转换为指针,然后被调用以输出该指针。void*
operator<<(const void*)
这可能不是你想要的:
godbolt
#include <iostream>
#include <sstream>
int main() {
std::stringstream m;
m << "foobar";
std::stringstream ss;
// equivalent to ss << static_cast<void*>(&m);
ss << m;
std::cout << ss.str() << std::endl;
// will print the address of m, e.g. 0x7ffcda4c2540
// NOT foobar!
return 0;
}
追加流的正确方法
C++ 可以通过传递底层流缓冲区而不是整个流来写入,例如:
godboltstd::istream
std::ostreams
#include <iostream>
#include <sstream>
int main() {
std::stringstream m;
m << "foobar";
std::stringstream ss;
ss << m.rdbuf(); // append everything from m to ss
std::cout << ss.str() << std::endl;
return 0;
}
所以你的例子可以这样修复:
// r << m;
r << m.rdbuf();
评论