临时stringstream对象可以使用吗?

8
这个可以正常运行:
stringstream temp;
temp << i;
result_stream << transform(temp.str());

(transform 是一个接受 string 并返回 string 的函数;i 是一个 int). 然而,我试图让 C++11 创建一个没有名称的临时对象却失败了:

result_stream << transform((stringstream() << i).str());

我原本以为这个方法是可行的,因为第二个<<操作符只会返回第一个参数,然后我可以在这个参数上使用str()。但是我遇到了以下错误:

error: 'class std::basic_ostream<char>' has no member named 'str'

我使用g++ 4.8.1 (MinGW-W64).
有没有办法实现这个(即使用未命名的临时变量编写此类代码)?(以上代码有点简化,实际代码涉及除int以外的参数使用<<。)

可能是使用匿名Stringstream构造字符串的重复问题。 - Jonathan Mee
这是一个特定的C++11问题吗? - curiousguy
4个回答

10

这个不起作用是因为第二个 <<std::ostream &operator<<(std::ostream &, int);,因此返回类型是 ostream&,它没有 str() 成员。

你需要写成:

result_stream << transform( static_cast<stringstream &>(stringstream() << i).str() );

更新(2019年):根据LWG 1203,标准可能会在将来发生更改(一个主要的实现已经进行了更改),因此此代码不再起作用,而更简单的代码则可以代替。详情请参见此问题

在过渡期内,显然以下内容适用于旧版和新版:

result_stream << transform( static_cast<stringstream &>(stringstream().flush() << i).str() );
//                                                                    ^^^^^^^^

这不应该对性能产生影响,因为清空一个空的流没有任何作用...


注意:最新的clang++编译器(9.0.0)会抱怨非const左值引用,因此为了进行强制转换,我们需要使用static_cast<const stringstream &>(stringstream() << i).str() - Krzysztof
@Krzysztof 在9.0.0中运行良好,也许你的代码有所不同。 - M.M
@M.M 抱歉,我没有提到我正在使用 MacOS。我已经复制粘贴了您的代码,但编译器报错 x.cc:12:24: error: non-const lvalue reference to type 'basic_stringstream<...>' cannot bind to a temporary of type 'basic_stringstream<...>' cout << transform( static_cast<stringstream &>(stringstream() << i).str() ); 在 g++ 9.2.0 中可以编译而没有任何问题。 - Krzysztof
1
@M.M 我已经针对那个问题创建了一个新的问题 - Krzysztof
@Krzysztof,LWG报告建议添加.flush()以使代码在stdlib实现上都能正常工作,即transform( static_cast<stringstream &>(stringstream().flush() << i).str() )--这对你有用吗?如果是的话,我会将其添加到我的答案中。 - M.M
显示剩余2条评论

6
<< 运算符在临时的 stringstream 上的结果是一个 ostreamostream 上没有 str() 方法。

使用 to_string 替代:

using std::to_string;

result_stream << transform(to_string(i));

您可以定义一个助手函数to_string来处理std::to_string不支持的对象。

template <typename T>
std::string to_string (const T &t) {
   std::ostringstream oss;
   oss << t;
   return oss.str();
}

例如,如果您有一个理解重定向到ostream的类Foo,并且fFoo的一个实例,则可以执行以下操作:
result_stream << transform(to_string(f));

在线试用!

如果您确实想要使用大量重定向来构建字符串,然后进行转换,您也可以为此创建一个辅助对象。
struct to_string_stream {
    std::ostringstream oss;
    template <typename T>
    auto & operator << (const T &t) { oss << t; return *this; }
    operator std::string () const { return oss.str(); }
    void clear () { oss.string(std::string()); }
};

然后,你可以做这样的事情:
to_string_stream tss;
result_stream << transform(tss << i << ':' << f);

在线试用!


6

operator<<()返回的是包含在std::stringstream中的基类std::ostream的引用。该基类不包含str()方法。你可以将其转换回std::stringstream&

result_stream << transform(static_cast<std::stringstream&>(std::stringstream() << i).str()); 

5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接