4

I use std::ostringstream for formatting strings, which inherits its << operators from ostream, and consequently they return an ostream and not an ostringstream, which means that I can't call ostringstream::str on the result. This usually isn't a problem, since I can typically do this:

ostringstream stream;
stream << whatever;
string str = stream.str();

But occasionally I need* to use it in just a single expression, which is more difficult. I could do

string str = ((ostringstream&) (ostringstream() << whatever)).str();

but bad things will happen if that << overload returns some ostream that isn't an ostringstream. The only other thing I can think to do is something like

string str = ([&] () -> string {ostringstream stream; stream << whatever; return stream.str();})();

but this can't possibly be efficient, and is certainly very bad c++ code.


*Okay, I don't need to, but it would be a lot more convenient to.

Anonymous
  • 491
  • 2
  • 12

3 Answers3

3

Using

string str = ([&] () -> string
             {
               ostringstream stream;
               stream << whatever;
               return stream.str();
              })();

is ok. However, I think it will be better to name that operation, create a function with that name, and call the function.

namespace MyApp
{
    template <typename T>
    std::string to_string(T const& t)
    {
        ostringstream stream;
        stream << t;
        return stream.str();
    }
}

and then use

string str = MyApp::to_string(whatever);
Justin
  • 24,288
  • 12
  • 92
  • 142
R Sahu
  • 204,454
  • 14
  • 159
  • 270
2

The only other thing I can think to do is something like

string str = ([&] () -> string {ostringstream stream; stream << whatever; return stream.str();})();

but this can't possibly be efficient, and is certainly very bad c++ code.

Actually, no. Once the optimizer has a look at this, it's exactly as fast as the original code. And it's not "very bad c++ code". It's known as an Immediately Invoked Lambda Expression, or IILE. It's an idiom, and actually quite decent practice.

It would be better formatted more like this, though:

// One of the benefits of IILEs is that `const` can be used more frequently
string const str = [&] {
    ostringstream stream;
    stream << whatever;
    return stream.str();
}();

Some people prefer using std::invoke to invoke the lambda instead:

string const str = std::invoke([&] {
    ostringstream stream;
    stream << whatever;
    return stream.str();
});
Justin
  • 24,288
  • 12
  • 92
  • 142
1

Assuming you got

std::string get_str(std::ostream& out) {
    retrun static_cast<std::stringbuf*>(out.rdbuf())->str();
}

You could use

std:: string s = get_str(std::ostringstream{} << ...);
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380