To a std::string
, you can only add other std::string
s, ASCIIZ text at an address specified by a const char*
, and individual char
-acters.
To concatenate other types, you can:
use a stream:
std::ostringstream oss;
oss << "we did " << a_uint << " and got " << result;
throw std::runtime_error(oss.str());
convert it first to a string representation:
throw std::runtime_error(std::string("we did ") +
boost::lexical_cast(a_uint) +
" and got " +
boost::lexical_cast(result));
You might reasonably wonder why C++ doesn't provide operator+(std::string&, X&)
for X in { short, int, long, long long, float, double, unsigned short etc. }, or even:
template <typename T>
std::string operator+(std::string& s, T& t)
{
std::ostringstream oss;
oss << t;
return s + oss.str();
}
In many cases it would be convenient. But streams are more powerful as you can tune the padding width and character, floating point precision etc.. Further, char is the 8-bit integer type, so how could the compiler know whether to append a single character with that ASCII value (e.g. 'A' for 65), or an ASCII representation of the numeric ASCII value "65"? (Currently it doesn't handle any ints, so treating it as a single ASCII char
isn't confusing). Or should it work for >=16 bit numbers but not 8? That would make it impossible to resize variables to/from 8-bit ints without having to do a complex impact analysis to see which string operations needed to be rewritten. It's also good practice to minimise dependencies: some small but perhaps significant percentage of translation units using string may not currently have to include (and hence spend time parsing) (and hence ostream etc), and in general cyclic dependencies are a "code smell" and frustrate testability (string depends on ostringstream depends on string...).