c ++ stringstream to ostream to string

Leo*_*Leo 3 c++ stl

我希望能够做到:

foo(stringstream()<<"number = " << 500);
Run Code Online (Sandbox Code Playgroud)

编辑:单线解决方案至关重要,因为这是用于记录目的.这些将围绕代码.

在foo里面会将字符串打印到屏幕或类似的东西.

现在因为stringstream的运算符<<返回ostream&,foo的签名必须是:

foo(ostream& o);
Run Code Online (Sandbox Code Playgroud)

但是如何将ostream转换为字符串呢?(或char*).实现此用例的不同方法也是受欢迎的.

Naw*_*waz 7

我建议您使用此实用程序结构:

struct stringbuilder
{
   std::stringstream ss;
   template<typename T>
   stringbuilder & operator << (const T &data)
   {
        ss << data;
        return *this;
   }
   operator std::string() { return ss.str(); }
};
Run Code Online (Sandbox Code Playgroud)

并将其用作:

void f(const std::string & s );

int main() 
{
  char const *const pc = "hello";

  f(stringbuilder() << '{' << pc << '}' );

  //this is my most favorite line
  std::string s = stringbuilder() << 25  << " is greater than " << 5 ;
}
Run Code Online (Sandbox Code Playgroud)

演示(还有几个例子):http : //ideone.com/J995r

更多关于我的博客:在一行中即时创建字符串


Jam*_*nze 6

显而易见的解决方案是使用dynamic_castfoo.但是给定的代码仍然不起作用.(你的例子将编译,但它不会做你认为应该做的.)表达式std::ostringstream()是临时的,你不能用临时初始化非const引用,并且第一个参数std::operator<<( std::ostream&, char const*) 是非const引用.(你可以在一个临时的.上调用一个成员函数std::ostream::operator<<( void const* ).所以代码会编译,但它不会做你期望的.

您可以使用以下方法解决此问题:

foo( std::ostringstream().flush() << "number = " << 500 );
Run Code Online (Sandbox Code Playgroud)

std::ostream::flush()返回一个非const引用,因此没有其他问题.在新创建的流上,它是一个无操作.不过,我认为你会同意它不是最优雅或最直观的解决方案.

在这种情况下我通常做的是创建一个包装类,它包含它自己的包装类std::ostringstream,并提供一个模板化的 成员 operator<<,它转发给包含的 std::ostringstream.你的函数fooconst 引用这个 - 或者我做的是foo直接调用析构函数 ,这样客户端代码甚至不必担心它; 它做的事情如下:

log() << "number = " << 500;
Run Code Online (Sandbox Code Playgroud)

该函数log()返回包装类的实例(但见下文),该类的(最终)析构函数调用您的函数 foo.

这有一个小问题.可以复制返回值,并在复制后立即销毁.哪个会破坏我刚刚解释的内容; 事实上,既然std::ostringstream不可复制,它甚至不会编译.这里的解决方案是将所有实际逻辑(包括std::ostringstream析构函数和析构函数逻辑调用的实例)foo放在一个单独的实现类中,使公共包装器具有一个boost::shared_ptr转发器和转发器.或者只是在类中重新实现一些共享指针逻辑:

class LogWrapper
{
    std::ostringstream* collector;
    int* useCount;
public:
    LogWrapper()
        : collector(new std::ostringstream)
        , useCount(new int(1))
    {
    }

    ~LogWrapper()
    {
        -- *useCount;
        if ( *useCount == 0 ) {
            foo( collector->str() );
            delete collector;
            delete useCount;
        }
    }

    template<typename T>
    LogWrapper& operator<<( T const& value )
    {
        (*collector) << value;
        return *this;
    }
};
Run Code Online (Sandbox Code Playgroud)

请注意,扩展它很容易支持可选的日志记录; 只需为LogWrapper提供一个构造函数,该构造函数设置collectorNULL,并在其中进行 测试operator<<.

编辑:

另一件事发生在我身上:你可能想要检查析构函数是否因异常而被调用,而不是foo在这种情况下调用 .从逻辑上讲,我希望你可能得到的唯一例外是std::bad_alloc,但总会有一个用户写下这样的东西:

log() << a + b;
Run Code Online (Sandbox Code Playgroud)

其中+是用户定义的重载抛出.