Table of Contents
SSTR()
Note: The C++11 construct std::to_string( x ) is more efficient than this. See end of article for perfomance comparisons.
Preface
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 << "\n";
Things get a bit more difficult when you want to get the result as a std::string (for example, as parameter to an exception constructor):
std::ostringstream s; s << "The value of i is " << i; std::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 ) static_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 returning not the original ostringstream object, but a reference 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 operator«().
static_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.
Performance
Nikos Athanasiou on StackOverflow benchmarked this construct in comparison to the more traditional Stringify( T const & value ) template function (also using std::stringstream), Boost lexical_cast<>, and C++11 to_string():
lexical_cast<string>() ... 125 to_string() .............. 250 SSTR .................... 1003 Stringify() ............. 1229
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." );
