【问题标题】:Use an Anonymous Stringstream to Construct a String使用匿名字符串流构造字符串
【发布时间】:2013-10-29 17:42:55
【问题描述】:

我想用这样的代码直接读入一个字符串:

std::string myString(( std::ostringstream() << myInt << " "
                                            << myFloat << " "
                                            << std::boolalpha << myBool ).str());

但是 VS2012 向我投诉 basic_ostream 没有 str() 方法。

有没有办法用匿名字符串流做到这一点?

【问题讨论】:

  • 此代码按原样编译并在 Clang 上运行良好。 (Apple LLVM 5.0 版(clang-500.2.79)(基于 LLVM 3.3svn))

标签: c++ string sstream


【解决方案1】:

流的operator&lt;&lt; 返回std::ostream &amp;,它没有str() 成员函数。您需要使用演员表。

static_cast<std::ostringstream&>(std::ostringstream() << etc).str()

使用临时流时 C++03 和 C++11 的区别!

C++03

但请注意(在 C++03 中)std::ostringstream() 创建了一个临时对象,这意味着不能为第一个 &lt;&lt; 调用 operator&lt;&lt;非成员 重载,因为它们都接受第一个参数为std::ostream&amp;,它不能绑定到临时对象。临时对象将能够调用只有成员函数。

这意味着,下面会给你 address 而不是 string

static_cast<std::ostringstream&>(std::ostringstream() << "XYZ").str()

因为以char const*为参数的重载是一个非成员函数,无法调用,所以上面的代码最终调用了以void const*为参数的成员函数,因此"XYZ" 被隐式转换为void const*,它打印字符串文字的地址

一旦临时调用成员函数,剩余的链式&lt;&lt;可能调用非成员重载,因为成员函数返回std::ostream&amp; 现在 可以绑定到operator&lt;&lt;非成员 重载的第一个参数。所以下面的代码将打印地址(而不是"XYZ"),然后是字符串"ABC"

static_cast<std::ostringstream&>(std::ostringstream() << "XYZ" << "ABC").str()

在线演示:

C++11

在 C++11 中,此问题已通过添加一个非成员函数 (27.7.3.9) 得到解决,该函数将第一个参数作为右值引用,然后将调用转发给适当的函数,无论是成员还是非成员.所以它打印XYZ,后跟ABC

【讨论】:

  • 非成员重载不能用于第一个&lt;&lt;。之后,您将拥有由第一个 &lt;&lt; 返回的 ostream&amp;(非常量)。通常的解决方案是从std::ostringstream().flush() &lt;&lt; ... 开始。 ostream::flush 是一个返回 ostream&amp; 的成员函数,当然,它实际上不会对您尚未写入的流执行任何操作。
  • @JamesKanze:我才知道在这种情况下 C++11 的行为有所不同。所以我之前描述的仅适用于 C++03。有了 C++11,我们就不再需要 flush() 把戏了!
  • 我似乎记得同样的事情,但我找不到标准中发生了什么变化。 (我认为它与右值引用有关;我不知道为什么。)
  • @JamesKanze:是的,27.7.3.9 为输出流引入了右值引用(输入流也有右值引用)。
  • @Nawaz 我知道该标准对 Microsoft 来说是一种建议,但在 Visual Studio 2010 中,我看到您的 C++11 代码有效。我以为 Visual Studio 2010 是 C++03?
【解决方案2】:

basic_osstream::operator&lt;&lt; 返回 basic_ostream,而不是 ostringstream。编译器没有骗你。

我宁愿创建一个 StringBuilder 类型的设备。

class StringBuilder
{
public:
    template <typename T> inline StringBuilder& operator<<(const T& t)
    {
        mStream << t;
        return * this;
    }
    inline std::string get() const
    {
        return mStream.str();
    }
    inline operator std::string () const
    {
        return get();
    }
private:
    std::stringstream mStream;
};

现在你可以:

std::string myString (StringBuilder() << myInt << " " << myFloat /*...*/);

Boost 中也有类似的设备 - 如果您可以使用这些设备,您最好使用它们。

【讨论】:

  • FWIW:这也是我的解决方案。
  • boost中的相似设备是什么。我自己在找。
【解决方案3】:

我也遇到了这个问题,John 的回答似乎很好,非常感谢! - 我尝试通过在 'stringstream' 上使用运算符'

这是一个不使用 g++ 编译但使用 clang(实验概念)编译的最小程序,已在 Compiler Explorer (godbolt.org) 中进行了测试:

#include <iostream>
#include <sstream>
#include <string>

int main()
{
   using namespace std;
   cout << ((stringstream() << "hola").str()) << endl ;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-02
    • 2020-07-26
    • 2016-08-02
    • 1970-01-01
    • 2013-05-05
    • 2010-11-19
    • 2015-06-28
    相关资源
    最近更新 更多