连接两个字符串文字


121

我正在阅读Koenig的Accelerated C ++。他写道:“新想法是,我们可以使用+来连接一个字符串和一个字符串文字-或两个字符串(但不能是两个字符串文字)。

很好,我想这很有道理。现在进行两个单独的练习来说明这一点。

以下定义是否有效?

const string hello = "Hello";

const string message = hello + ",world" + "!";

现在,我尝试执行以上操作,它成功了!所以我很高兴。

然后,我尝试进行下一个练习;

const string exclam = "!";

const string message = "Hello" + ",world" + exclam;

这没有用。现在,我知道这与不能连接两个字符串文字的事实有关,但是我不理解为什么我设法使第一个示例生效(不是“,world”和“!”之间的语义差异。 “两个字符串文字?这不应该行得通吗?)但是第二个不是。


4
const string message = "Hello" ",world" + exclam(例如,省略第一个+)应该工作正常。
2011年

1
@Joe-为什么有人"Hello" + ", world!"在可以的时候写东西"Hello, world!"。像往常一样,C ++为解决已知问题提供了一种很棒且简单的解决方法。:-)
Bo Persson

2
@Bo我唯一能想到的就是使用定义(#define)
Joe Phillips

@Joe即使那样,您也更有可能写"Hello" ", world!"(没有+)。人们可能会对C ++提出很多抱怨,但是我不认为这是其中之一。这与您编写1 / 3 + 1.5并抱怨的原因完全相同,因为该除法是整数除法。无论好坏,这是大多数语言工作的方式。
詹姆斯·坎泽

2
@Bo Persson实际上,"hello" " world" == "hello world"如果您必须编写一个长字符串并且不希望它超出窗口范围,或者您希望处于某个行长限制范围内,则此功能很有用。或者,如果在宏中定义了字符串之一。
Dimitar Slavchev

Answers:


140
const string message = "Hello" + ",world" + exclam;

+运算符具有从左到右的关联性,因此等效的括号表达式为:

const string message = (("Hello" + ",world") + exclam);

如您所见,两个字符串文字"Hello"",world"被首先“添加”,因此出现错误。

要串联的前两个字符串之一必须是一个std::string对象:

const string message = string("Hello") + ",world" + exclam;

或者,您可以+通过在表达式的该部分加上括号来强制首先计算第二个:

const string message = "Hello" + (",world" + exclam);

第一个示例(hello + ",world" + "!")有效是有道理的,因为std::stringhello)是最左边的参数之一+。即+进行评价时,其结果是std::string与串联的字符串对象,并且该所得std::string然后与级联"!"


至于为什么不能使用来连接两个字符串文字+,这是因为字符串文字只是一个字符数组(const char [N]其中a N是字符串的长度加一个,对于空终止符)。当您在大多数情况下使用数组时,它会转换为指向其初始元素的指针。

因此,当您尝试执行操作时"Hello" + ",world",您真正要执行的操作是将两个const char*s加在一起,这是不可能的(将两个指针加在一起意味着什么?),如果这样做,您将不执行任何操作想要它做。


注意,可以通过将字符串文字彼此相邻来连接它们;例如,以下两个是等效的:

"Hello" ",world"
"Hello,world"

如果您有一个很长的字符串文字要分解成多行,这将很有用。但是,它们必须是字符串文字:这不适用于const char*指针或const char[N]数组。


3
而且,const string message = "Hello" + (",world"+exclam);由于显式括号(这是一个词吗?),它也将起作用。
2011年

1
如果您指出第一个示例的工作原因,可能会更加完整:const string message = ((hello + ",world") + "!");
Mark Ransom

谢谢!我怀疑这与从左到右的关联性有关,但是不确定,这种语义上的差异对我来说意义不大。感谢您的回答!
亚瑟·科雷(ArthurCollé)2011年

2
我要提到的"Hello" ",world"语法不仅对于分成多行很有用,而且在字符串文字之一是宏(甚至是两者)时也很有用。然后,串联发生在编译时。
Melebius

8

您应该始终注意类型

尽管它们看起来都像字符串,"Hello"而且",world"都是文字

在您的示例中,exclam是一个std::string对象。

C ++具有运算符重载,该重载接受一个std::string对象并向其添加另一个字符串。将std::string对象与文字连接时,它将对文字进行适当的转换。

但是,如果尝试连接两个文字,那么编译器将无法找到需要两个文字的运算符。


请参阅std :: operator +,其中提供了用于将a std::string与另一个std::string,一个字符数组或单个字符连接的重载。
DavidRR

7

您的第二个示例不起作用,因为没有operator +两个字符串文字。请注意,字符串文字不是type string,而是type const char *。如果您这样修改第二个示例,它将起作用:

const string message = string("Hello") + ",world" + exclam;

4

从C ++ 14开始,您可以使用两个真实的字符串文字

const string hello = "Hello"s;

const string message = hello + ",world"s + "!"s;

要么

const string exclam = "!"s;

const string message = "Hello"s + ",world"s + exclam;

2

在情况1中,由于操作顺序,您得到:

(你好+“世界”)+“!” 解析为hello +“!” 最后打招呼

如James所述,在情况2中,您将获得:

(“ Hello” +“,world”)+ exclam,这是2个字符串文字的结合。

希望很清楚:)


1

字符串(准确地说是std::string)和字符文字之间的区别在于,对于后者,没有+定义运算符。这就是第二个示例失败的原因。

在第一种情况下,编译器可以找到一个合适operator+的参数,第一个参数为a string,第二个参数为字符文字(const char*),因此使用它。该操作的结果再次是a string,因此在添加时重复相同的技巧"!"

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.