Printing a string to a temporary stream object in C++

天涯浪子 提交于 2019-11-29 15:03:01

The overload ostream& operator<< (ostream& out, const char*) is not viable because your temporary won't bind to the non-const reference ostream&. There isn't really much you can do about that (since you can't cast an rvalue to an lvalue) other than declaring a local variable and using that:

{
  specialstringstream ss;
  ss << "Hello world" << std::endl; // OK, can bind to lvalue
}

Possible solution: You could declare another overload that accepts an rvalue reference:

std::ostream & operator<<(specialstringstream && o, const char * s)
{
  return o << s; // note: *not* "std::move(o)"
}

You don't want to implement stringstream. You want to implement a basic_streambuf that writes into your special string.

The streams themselves are responsible for formatting and similar functions; the streambufs are responsible for what ultimately becomes the sink for the data.

After all, all a stringstream is is a iostream, with a basic_stringbuf attached.

Maybe there is some better way but i figured an other solution:

#include <iostream>
#include <sstream>

class LogClass
{ 
    template <typename T>
    friend const LogClass& operator << (const LogClass& lc, const T& v);
public:
    LogClass()
        : str(new std::ostringstream())
        , refCount(new int(1))
    {}

    LogClass(const LogClass& other)
        : str(other.str)
    {
        ++(*refCount);
    }

    ~LogClass()
    {
        --(*refCount);
        if (!*refCount)
        {
            delete refCount;
            std::cout << str->str() << std::endl;
            delete str;
        }
    }
private:
    mutable std::ostringstream *str;
    int *refCount;

    LogClass& operator = (const LogClass&);
};

template <typename T>
const LogClass& operator << (const LogClass& lc, const T& v)
{
    (*lc.str) << v;
    return lc;
}

int main(int , char**)
{
    for (size_t i = 0; i < 10 ; ++i)
    {
        LogClass() << "PARTY DOWN! " << i;
    }
}

Running it with valgrind:

valgrind --tool=memcheck --leak-check=full ./LogClass

==16197== Memcheck, a memory error detector

==16197== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.

==16197== Using Valgrind-3.7.0.SVN and LibVEX; rerun with -h for copyright info

==16197== Command: ./LogClass

==16197==

PARTY DOWN! 0

PARTY DOWN! 1

PARTY DOWN! 2

PARTY DOWN! 3

PARTY DOWN! 4

PARTY DOWN! 5

PARTY DOWN! 6

PARTY DOWN! 7

PARTY DOWN! 8

PARTY DOWN! 9

==16197==

==16197== HEAP SUMMARY:

==16197== in use at exit: 0 bytes in 0 blocks

==16197== total heap usage: 40 allocs, 40 frees, 7,350 bytes allocated

==16197==

==16197== All heap blocks were freed -- no leaks are possible

==16197==

==16197== For counts of detected and suppressed errors, rerun with: -v

==16197== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 15 from 8)

Thats what i wanted, but it is not thread safe. Use shared_ptr from boost to make it so.

here is a workaround I'm using:

#define STRM2STR(x) (dynamic_cast<std::ostringstream &>(std::ostringstream() << std::dec << x).str())

insertion of std::dec will result in calling ostream::operator<< (ios_base& (*pf)(ios_base&)) which returns usable ostream &

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!