这两种添加字符串的情况有什么区别?

时间:2015-09-13 22:26:05

标签: c++ string c++11

我注意到,当我初始化一个字符串时,编译器报告了一个我没想到的错误。

例如:

#include <iostream>
#include <string>

using namespace std;

int main() {
    string s1 = "Hello", s2 = "World!"; // ok
    string s3 = s1 + ", " + "World!"; // ok
    string s4 = "Hello" + ", " + s2; // error
    cout << s1 + " " + s2 << endl; //ok
    return 0;
}

对我来说,如果s3工作得很好,s4也应该这样做。

为什么我会收到该错误?这两个初始化字符串(s3s4)之间有什么区别?

5 个答案:

答案 0 :(得分:13)

"Hello"不是std::string(而是const char[6],而", "const char[3])和+运营商std::string不适用。

这对C ++来说是一个小小的不便,源于它的C系列。这意味着在通过+连接字符串时,必须确保其两个操作数中至少有一个实际上是std::string,如

auto s = std::string{"Hello"} + ", " + "World";

其中第一个+std::string作为其第一个操作数,因此产生std::string,因此第二个+也有一个std::string它的第一个操作数(从+开始从左到右处理)。

T.C.的评论提示

Edit1 ,我提到如果只用空格分隔,C字符串文字会自动连接:

std::string s = "Hello" ", " "World";

此行为也是从C继承的:预处理器将上面的代码呈现为

std::string s = "Hello, World";

在编译器正确处理它之前(更准确地说,字符串连接发生在转换的phase 6中,就在编译之前)。这实际上是连接原始字符串文字的最简单,也是最方便的方法。但请注意,我必须声明s的类型,因为auto扣除会产生const char*

PaperBirdMaster的评论提示

Edit2 ,我提到自C ++ 14以来,您只需添加std::string后即可直接形成s文字字符串 if 你拉入相关的operator""s(或周围的命名空间)。

using std::literals::operator""s;                // pull in required operator
const auto s = "Hello"s + ", " + "World";        // std::string

请参阅this post,了解嵌套命名空间中隐藏所需operator""s的原因。另请注意,除using std::literals::operator""s;之外,您可以拉入周围的namespace:以下任一声明都可以。

using namespace std::string_literals;
using namespace std::literals::string_literals;
using namespace std::literals;

并不像普通using namespace std;那样糟糕(和该死)。

答案 1 :(得分:5)

以下行尝试将2个指针添加到一起。

string s4 = "Hello" + ", " + s2; // error

"Hello"是一个const char[6],其衰减为const char*", "是一个变为char[3]的衰变为const char*

您正在尝试为std::string添加两个指针,这是无效的。此外,添加两个指针也无效。

正如其他人所说,这与operator+类的std::string的重载没有任何关系,因为以下代码也不会因为同样的原因而编译:

string s4 = "Hello" + ", ";

我添加了一些用户 @dyp 提供的说明。

您可以使用C ++标准库&#34;用户定义&#34;来解决您的问题。字符串字面量。该功能由std::literals::string_literals::operator""s提供,可在<string>标头中找到。您可能必须使用using-directive或-declaration;我的编译器不需要这个,包括<string>标题就足够了。例如:

string s4 = "Hello"s + ", "s + s2;

这相当于:

string s4 = std::string("Hello") + std::string(", ") + s2;

当您将std::string的实例作为第一个操作数时,表达式的其余部分将使用该类型,因为operator +的左右关联将确保std::string的实例是每次都返回最左边的操作数,而不是const char*。这就是为什么你没有在线错误:

string s3 = s1 + ", " + "World!";

该行相当于:

string s3 = ((s1 + ", ") + "World!");

答案 2 :(得分:5)

字符串和C字符串

在C ++中,字符串通常表示为std::stringC-string,其类型为char[N],其中N是C字符串中的字符数加上一个用于终止字符(或空字符)\0

将字符串文字作为例如"Hello"传递给函数时,实际上是在传递char[6]衰减指针char*,因为C ++不允许您按值传递数组。此外,C ++ 允许非常量指针指向字符串文字,因此参数类型必须变为const char*

级联

std::string具有binary addition operator的现有重载,允许您将两个std::string对象连接成一个,以及将std::string对象与C字符串连接起来。

std::string s1 = "Hello";
std::string s2 = "World";

// Uses 'std::string operator+(const std::string&, const std::string&)'.
std::string s3 = s1 + s2;

// Uses 'std::string operator+(const std::string&, const char*)'.
std::string s4 = s1 + "World";

// Also ok.
std::string s4 = "Hello" + s2;

但是,连接两个C字符串没有重载。

// Error. No overload for 'std::string operator+(const char*, const char*)' found.
std::string s5 = "Hello" + "World";

从左到右

在C ++中执行添加left to right,因此,长连接表达式需要以std::string对象开头。

std::string s6 = "Hello" + ", " + s2; // Error. Addition is performed left-to-right and
                                      // you can't concatenate two C-strings.

std::string s7 = s1 + ", " + "World"; // Ok. 's1 + ", "' returns a new temporary
                                      // 'std::string' object that "World" is concat'ed to.

一个简单的解决方案

使用C ++ 14 标准文字,您可以从文字表达式创建std::string个对象(请注意文字表达式中的尾随s)。

using namespace std::literals;
std::string s8 = "Hello"s + ", " + "World"; // Ok

或者,您可以使用预处理器将自动连接用空格分隔的文字字符串这一事实。

std::string s9 = "Hello" ", " "World"; // Ok

但是,你可以完全跳过这个空格并使用单个字符串文字。

答案 3 :(得分:3)

首先要理解的是,由于C语言中的祖先,C ++中的字符串文字如"Hello" 而不是实际上是string类型。它的类型实际上是一个字符数组。

因此,s3s4之间的区别在于,当您执行s3构造时,完成的第一个操作是s1 + ", "s1的类型为字符串,因此使用标准库的字符串组件提供的+运算符,并返回要添加到"World!"的新字符串。

现在,对于s4,要执行的第一个操作是"Hello" + ", "或添加两个字符串文字。这个操作实际上会被编译器视为将两个字符数组一起添加,这种语言不能提供这种功能,从而导致您看到的错误。

最简单的解决方法是不要将+用于字符串文字,只需将它们放在同一个字符串中即可。或者,您可以从第一个文字创建string并让操作从那里开始工作(std::string("Hello") + ", " + s2

答案 4 :(得分:2)

+运算符在std :: string中重载。 运算符重载应用于操作数,因此 s1 + ...通过调用s1上的重载+运算符来工作。

文字"Hello"const char *","也是const char *string("Hello") + ...没有重载+运算符,因此出错。 试试fixed property.即可。

感谢@interjay的修正