wiki:SSTR()

Note: This construct is mostly obsolete since C++11 made its appearance. Use std::to_string( x ) instead.


Quite frequently, a C++ coder will face the issue of turning some value or object into its string representation (usually for output of some kind). Conveniently, when you want to write to terminal or a file, this can be done quite easily using the commonplace operator<<() syntax:

int i = 42;
std::cout << "The value of i is " << i << std::endl;

Things get a bit more difficult when you want to get the result as a string (for example, as parameter to an exception constructor):

ostringstream s;
s << "The value of i is " << i;
string output = s.str();

There are several footholes to be aware of, and anyway writing up those lines over and over again can become quite tedious. Thus, I present to thee:

The SSTR() macro

By no means an invention of myself, I first came across this construct in 2002. Since then, it has followed me to whatever C++ code I was working upon. Without further ado:

#include <sstream>

#define SSTR( x ) dynamic_cast< std::ostringstream & >( \
                  std::ostringstream() << std::dec << x ).str()
  • std::ostringstream()

Creating an anonymous ostringstream object with which we will construct the string.

  • << std::dec

Setting the integer output format to "decimal" looks like a non-op since decimal is the default anyway. However, it has the effect of turning the type of our object from ostringstream to ostream &. This is important if the first data element given to the macro is a pointer (e.g. a C-style string): If we would use the ostringstream object directly, function lookup would use ostream::operator<<( void * ) in this case (giving us a boolean value) instead of the global operator<<( ostream &, char const * ) we want (giving us a string output).

Other versions of this macro that I came across in the 'net use the non-op construct std::ostringstream().seekp( 0, std::ios_base::cur ) to get at that ostream & return value. However, that construct is known to break on Microsoft Visual C++ 2005, and possibly some others, whereas the std::dec trick worked on any platform I have been working on so far, including Solaris and AIX.

  • << x

...passes the macro parameter(s) verbatim. This could be a single data value, or any number of values daisy-chained with more << operators.

  • dynamic_cast< std::ostringstream & >( ... )

We turned our ostringstream object into a ostream reference, and "piped" all our output to it. Now we want to extract the accumulated string from the object; but the member function str() that would do this for us is not defined for ostream, only for ostringstream. So we cast our ostream reference back to the correct type...

  • ().str()

...and extract the string.

I have not profiled the construct, but a smart compiler with a sufficiently smart library implementation should be able to optimize most of the implied code away. Should someone have hard facts on this, feel free to drop me a mail (at solar@...), and I will publish them here.

Usage

int i = 42;
std::string s1 = SSTR( i );
std::string s2 = SSTR( "Value of i is: " << i );
std::string s3 = SSTR( i << " is the answer to the universe, life, and everything." );
Last modified 13 months ago Last modified on 2013-10-16T13:23:06+02:00