将int添加到std::string中

42

我尝试了两种不同的方法来将一个 int 添加到一个 std::string 中,令我惊讶的是,我得到了不同的结果:

#include <string>

int main()
{
    std::string s;
    s += 2;     // compiles correctly
    s = s + 2;  // compiler error

    return 0;
}

当我使用+=运算符时,为什么它编译并正确工作,但当我使用+运算符时失败?

我认为这个问题不像如何连接std :: string和int?

在那个问题中,没有答案使用 += 运算符。而 std :: string += + 运算符之间的差异是解决我的疑惑的关键。

坦白地说,这个问题是解释为什么C ++难以掌握的好例子。


9
无论哪种情况,您都没有添加整数“2”的字符串表示。您需要使用std::to_string函数。 - Jesper Juhl
1
我不确定,但我认为operator+期望一个string而不是一个int - Bo Halim
13
你无法将一个 int 类型的值直接附加到字符串中。你可以将代表整数值的 文本 附加到字符串中,但不要忽略转换步骤。请注意保留此转换过程。 - Pete Becker
3
可能是 如何将 std::string 和 int 拼接起来? 的重复问题。 - Cole Tobin
4个回答

52
TL;DRoperator+=class string 的成员函数,而 operator+ 是一个模板函数。
标准类模板 template<typename CharT> basic_string<CharT> 重载了函数 basic_string& operator+=(CharT),而字符串只是 basic_string<char>
由于适合较低类型的值可以自动转换为该类型,在表达式 s += 2 中,数字 2 不被视为 int,而是被视为 char。它会产生与 s += '\x02' 完全相同的效果。追加的是 ASCII 码为 2(STX)的字符,而不是数字 '2'(其 ASCII 值为 50 或 0x32)。
然而,字符串并没有像 string operator+(int) 这样的重载成员函数,因此 s + 2 不是有效的表达式,在编译期间会引发错误。(更多内容详见下文)
你可以用以下方式在字符串中使用 operator+ 函数:
s = s + char(2); // or (char)2
s = s + std::string(2);
s = s + std::to_string(2); // C++11 and above only

对于那些关心为什么使用operator+时2不会自动转换为char的人,


template <typename CharT>
  basic_string<CharT>
  operator+(const basic_string<CharT>& lhs, CharT rhs);

上述是在 s + 2 中加法运算符的原型[注],因为它是一个模板函数,所以需要实现 operator+<char>operator+<int>,这两者是冲突的。详情请参见为什么模板函数不适用于自动向下转换?

与此同时,operator+= 的原型是:

template <typename CharT>
class basic_string{
    basic_string&
      operator+=(CharT _c);
};

你看,这里没有模板(它是类成员函数),所以编译器从类实现推断出类型CharT是char,并且int(2)自动转换为char(2)


注意:从C++标准库源代码复制时,会剥离不必要的代码。这包括模板类“basic_string”中的typename 2和3(Traits和Allocator),以及不必要的下划线,以提高可读性。


为什么表达式s + 2中的数字2不被视为char,而在s += 2中却是? - Andre Kampling
1
@AndreKampling:这与+=是非模板函数而+是模板函数有关。 - Bathsheba

45

s += 2;并不是你想象中的那样。它会调用重载的+=运算符,对一个char进行操作。它不会添加字符'2',而是添加值为2的字符,结果将取决于您平台上使用的编码方式

没有定义允许s + 2编译的运算符重载1,因此会出现错误。

在这两种情况下的解决方法都是使用std::to_string(2)而不是int字面量2。


1本质上的原因是operator+=不是一个模板函数,但std::operator+是一个模板函数,重载决议会优先选择非模板函数。


2
但我不明白为什么编译器调用 string& operator+= (char c); 而不是 string operator+ (const string& lhs, char rhs); - Andre Kampling
1
我想这本身就是个不错的问题(与编译器必须尝试将2转换为std::string有关,但它做不到)。为什么不问呢? - Bathsheba
1
@AndreKampling:我认输了,加入了更多的细节。 - Bathsheba
2
s += 2 能够编译通过,这实在感觉像是一个缺陷。 - Tristan Brindle
2
请参考这个问题,它涉及到关于为什么模板函数不会自动进行向下转型的问题:为什么模板函数不会自动进行向下转型? - Andre Kampling
显示剩余5条评论

14

string 添加的正确方式如下:

std::string s;
s += std::to_string(2);
s = s + std::to_string(2);

3
请注意,std::to_string 仅在 C++11 及更高版本中可用。 - Andre Kampling
5
@AndreKampling 现在是2017年。除非问题明确标记或提到C++03,否则可以合理地假设支持C++11。 - aschepler
1
通常推荐将对象输出为字符串的方法是使用std::ostringstream,将对象流式传输到其中,然后使用.str()函数从std::ostringstream获取std::string。这适用于所有C++方言和具有插入运算符的所有对象。 - CSM
6
“generally recommended”是什么意思?为什么会这样说?在这种情况下,函数std::to_string是完全合理的,并且就是为了这个目的而创建的。 - Cory Kramer

2
虽然@CoryKramer的回答给出了将整数添加到字符串的正确方法,但它没有解释为什么指令 s = s + 2 无法编译。
两个指令之间的区别在于,在第一个指令中,您使用std :: string's {{link1:+ =运算符}},而在第二个指令中,编译器试图将2转换为字符串。 intstd :: string之间没有隐式转换。但是,您可以将int转换为char,因此这就是为什么s + = 2有效的原因。

s = s + 2 不会崩溃,但编译会失败。 - Bathsheba
s + 2不能编译,但s + '\x02'可以。你如何解释? - iBug
@iBug 我相信这与 '\x02' 是一个字符有关,加号运算符知道如何将一个字符添加到字符串中,因为字符串本质上是一个花哨的字符数组。 - CCD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接