c ++ stringstream to ostream to string [英] c++ stringstream to ostream to string

查看:159
本文介绍了c ++ stringstream to ostream to string的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要能够:

  foo(stringstream()<<number = ; <500); 

编辑:单行解决方案至关重要,因为这是为了记录目的。这些将在代码周围。



在foo内部将打印字符串到屏幕或某种排序。



现在由于stringstream的运算符<<返回ostream& foo的签名必须是:

  foo(ostream& o); 

但是如何转换ostream&到字符串? (或char *)。

解决方案

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



你可以使用类似的方法解决这个问题:

  foo(std :: ostringstream()。flush()<<number =< <500); 

std :: ostream :: flush()返回一个非const引用,所以没有
进一步的问题。在一个新创建的流,它是一个无操作。
仍然,我认为你会同意,这不是最优雅或直观的$ b $在这种情况下,我通常做的是创建一个包装类,其中
包含它自己的 std :: ostringstream



,并提供一个模板化的
成员 运算符<< code> std :: ostringstream
。你的函数 foo 会取一个 const
引用这个—或者我离开做的是直接调用
foo ,以便客户端代码甚至不必担心关于
it;它会做类似的事情:

  log()< number =< 500; 

函数 log()的封装类(但是看下面的
),这个类的(final)析构函数调用你的函数
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))
{
} b
$ b〜LogWrapper()
{
- * useCount;
if(* useCount == 0){
foo(collector-> str());
delete collector;
delete useCount;
}
}

template< typename T>
LogWrapper&运算符<<(T const& value)
{
(* collector)<值;
return * this;
}
};

请注意,很容易将其扩展为支持可选日志记录;只是
为LogWrapper提供了一个构造函数,它将 collector 设置为
NULL 运算符



已编辑:



还有一件事发生在我身上:你可能想要检查
析构函数是否被作为异常的结果调用,而不是调用
foo 在这种情况下。逻辑上,我希望
可能获得的唯一的例外是 std :: bad_alloc ,但总是有一个用户
例如:

  log()< a + b; 

其中 + 是用户定义的重载这引发了。


I would like to be able to do:

foo(stringstream()<<"number = " << 500);

EDIT: single line solution is crucial since this is for logging purposes. These will be all around the code.

inside foo will print the string to screen or something of the sort.

now since stringstream's operator<< returns ostream&, foo's signature must be:

foo(ostream& o);

but how can I convert ostream& to string? (or char*). Different approaches to achieving this use case are welcome as well.

解决方案

The obvious solution is to use dynamic_cast in foo. But the given code still won't work. (Your example will compile, but it won't do what you think it should.) The expression std::ostringstream() is a temporary, you can't initialize a non-const reference with a temporary, and the first argument of std::operator<<( std::ostream&, char const*) is a non-const reference. (You can call a member function on a temporary. Like std::ostream::operator<<( void const* ). So the code will compile, but it won't do what you expect.

You can work around this problem, using something like:

foo( std::ostringstream().flush() << "number = " << 500 );

std::ostream::flush() returns a non-const reference, so there are no further problems. And on a freshly created stream, it is a no-op. Still, I think you'll agree that it isn't the most elegant or intuitive solution.

What I usually do in such cases is create a wrapper class, which contains it's own std::ostringstream, and provides a templated member operator<< which forwards to the contained std::ostringstream. Your function foo would take a const reference to this—or what I offen do is have the destructor call foo directly, so that the client code doesn't even have to worry about it; it does something like:

log() << "number = " << 500;

The function log() returns an instance of the wrapper class (but see below), and the (final) destructor of this class calls your function foo.

There is one slight problem with this. The return value may be copied, and destructed immediately after the copy. Which will wreck havoc with what I just explained; in fact, since std::ostringstream isn't copyable, it won't even compile. The solution here is to put all of the actual logic, including the instance of std::ostringstream and the destructor logic calling foo in a separate implementation class, have the public wrapper have a boost::shared_ptr to it, and forward. Or just reimplement a bit of the shared pointer logic in your class:

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;
    }
};

Note that it's easy to extend this to support optional logging; just provide a constructor for the LogWrapper which sets collector to NULL, and test for this in the operator<<.

EDITED:

One other thing occurs to me: you'll probably want to check whether the destructor is being called as a result of an exception, and not call foo in that case. Logically, I'd hope that the only exception you might get is std::bad_alloc, but there will always be a user who writes something like:

log() << a + b;

where the + is a user defined overload which throws.

这篇关于c ++ stringstream to ostream to string的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆