I tried two different ways to append an int
to a std::string
, and to my surprise, I got different results:
#include <string>
int main()
{
std::string s;
s += 2; // compiles correctly
s = s + 2; // compiler error
return 0;
}
Why does it compile and work correctly when I use the +=
operator, but fail when I use the +
operator?
I don't think the question is like How to concatenate a std::string and an int?
In that question,no answer uses +=
operator.And the difference between +=
and +
operator of std::string
is the key to solve my doubt.
Frankly,the question is a good example for explaining why c++ is so difficult to master.
TL;DR operator+=
is a class member function in class string
, while operator+
is a template function.
The standard class template<typename CharT> basic_string<CharT>
has overloaded function basic_string& operator+=(CharT)
, and string is just basic_string<char>
.
As values that fits in a lower type can be automatically cast into that type, in expression s += 2
, the 2 is not treated as int
, but char
instead. It has exactly the same effect as s += '\x02'
. A char with ASCII code 2 (STX) is appended, not the character '2' (with ASCII value 50, or 0x32).
However, string does not have an overloaded member function like string operator+(int)
, s + 2
is not a valid expression, thus throws an error during compilation. (More below)
You can use operator+ function in string in these ways:
s = s + char(2); // or (char)2
s = s + std::string(2);
s = s + std::to_string(2); // C++11 and above only
For people concerned about why 2 isn't automatically cast to char
with operator+
,
template <typename CharT>
basic_string<CharT>
operator+(const basic_string<CharT>& lhs, CharT rhs);
The above is the prototype[note] for the plus operator in s + 2
, and because it's a template function, it is requiring an implementation of both operator+<char>
and operator+<int>
, which is conflicting. For details, see Why isn't automatic downcasting applied to template functions?
Meanwhile, the prototype of operator+=
is:
template <typename CharT>
class basic_string{
basic_string&
operator+=(CharT _c);
};
You see, no template here (it's a class member function), so the compiler deduces that type CharT is char
from class implementation, and int(2)
is automatically cast into char(2)
.
Note: Unnecessary code is stripped when copying from C++ standard include source. That includes typename 2 and 3 (Traits and Allocator) for template class "basic_string", and unnecessary underscores, in order to improve readability.
s += 2;
is not doing what you think it's doing. It calls the overloaded +=
operator to a char
. It does not append the character '2'
, but rather the character with value 2, and the result will depend on the encoding used on your platform.
There is no operator overload defined to allow s + 2
to compile1. Hence the error.
The solution in both cases is to use std::to_string(2)
rather than the int
literal 2.
1 Essentially the reason is because operator+=
is not a template function, but std::operator+
is, and overload resolution will favour a non-template function over a template one.
The correct way to add to your string
would be
std::string s;
s += std::to_string(2);
s = s + std::to_string(2);
While @CoryKramer answer gives you the correct way to add an integer to a string, it doesn't explain why the instruction s = s + 2
does not compile.
The difference between the two instruction is that in the first one you use the std::string
's += operator while in the second instruction, the compiler tries to cast 2
to a string.
There is no implicit conversion between int
and std::string
. however, you can cast an int
to char
, so this is why s += 2
works.