Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have a special type of ostringstream that I am trying to output text to as a temporary object but I'm having some trouble. To be clear, this is essentially what I want to do:

ostringstream() << "PARTY DOWN!" << endl;

Now before you say: "But Zack, that code is totally worthless! The object is destroyed at the end of the line, how would you even know if it did anything?", hear me out. I don't try to do this with plain ostringstreams, but rather a derived class in which the destructor actually provides a path for the data to exit the object. So in reality, it looks a lot more like this:

specialstringstream() << "PARTY DOWN!" << endl;

Where specialstringstream has a destructor which dumps the text elsewhere.

I won't go into too much detail as to why I do this. You'll have to trust me that it makes sense for what I need to do and it fits nicely into an existing, gigantic codebase.

Here's the problem: when I do this, everything compiles and runs, but I get a pointer address printed to my output instead of the "PARTY DOWN!" string. I determined that this is happening because the operator chosen by the compiler to perform the stream output is ostream& operator<< (const void* val), not ostream& operator<< (ostream& out, const char* s ).

I have a vague idea of why but I'm at a loss as to how to work around it. What can I do to get char*s to print into a temporary instance of a stringstream?

Here's a short version of the SpecialStringStream object that exhibits the behavior:

class SpecialStringStream : public ostringstream
{
  public:
    SpecialStringStream(ostream* regularStream)
    {
      regularStream_ = regularStream;
    }

    ~SpecialStringStream()
    {
      if (regularStream_ != NULL)
        (*regularStream_) << str(); 
    }

  private:
    ostream* regularStream_;
};

When I do something like: SpecialStringStream(someStreamPtr) << "PARTY DOWN!" << endl;, I get a pointer address like "00444D60" in my output instead of the message.

EDIT: Since I am too new of a user to answer my own question, here is what I've settled on thanks to all the responses.

I came up with the following solution, which works under Visual C++ 8 and all of the other compilers I needed it to. I created a template operator which basically strips a const SpecialStringStream of its constness, casts it as an ostream, and lets the ostream operators do their thing. Feel free to tear it to shreds in the comments and warn me of all the horrible potential bugs I've introduced!

template <class T>
std::ostream& operator<<(const SpecialStringStream &o, T msg)
{
    return static_cast<std::ostream&>(const_cast<SpecialStringStream&>(o)) << msg;
}
like image 757
Zack Schilling Avatar asked Nov 04 '11 18:11

Zack Schilling


1 Answers

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)"
}
like image 81
Kerrek SB Avatar answered Sep 27 '22 19:09

Kerrek SB