簡體   English   中英

這兩種添加字符串的情況有什么區別?

[英]What is the difference between these two cases of adding a string?

我注意到,當我初始化一個字符串時,編譯器報告了一個我沒想到的錯誤。

例如:

#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 )之間有什么區別?

"Hello"不是std::string (而是const char[6] ,而", "const char[3] ), std::string s的+運算符不適用。

這是C ++的一個小小的不便,源於它的C系列。 這意味着在通過+連接字符串時,必須確保其兩個操作數中的至少一個實際上是std::string ,如

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

其中第一個+有一個std::string作為它的第一個操作數,因此產生一個std::string ,所以第二個+也有一個std::string作為它的第一個操作數(因為+從左到右處理)。


TC的注釋提示Edit1 ,我提到如果只用空格分隔,C字符串文字會自動連接:

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

此行為也是從C繼承的:預處理器將上面的代碼呈現給

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

在編譯器正確處理它之前(更准確地說,字符串連接發生在轉換的第6階段 ,就在編譯之前)。 這實際上是連接原始字符串文字的最簡單,也是最方便的方法。 但請注意,我必須聲明s的類型,因為auto推斷會給出一個const char*


PaperBirdMaster的評論提示Edit2 ,我提到自從C ++ 14以來, 如果你拉入相關的operator""s (或周圍的命名空間),你可以直接在字符串之后添加s來直接形成std::string文字。

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

請參閱這篇文章 ,了解為什么所需的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;並沒有那么糟糕(和該死) using namespace std;

以下行嘗試將2個指針添加到一起。

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

"Hello"是一個const char[6] ,衰變為const char*", "是一個const char[3] ,它衰變為const char*

您正嘗試將兩個指針添加到std::string ,這是無效的。 此外,添加兩個指針也無效。

正如其他人所說,這與std::string類的operator+的重載沒有任何關系,因為以下代碼也不會因為同樣的原因而編譯:

string s4 = "Hello" + ", ";

我添加了一些用戶@dyp提供的說明

您可以使用C ++標准庫“用戶定義的”字符串文字來解決您的問題。 該功能由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!");

字符串和C字符串

在C ++中,字符串通常表示為任一std::string或一個C-串 ,其具有類型char[N]其中N是在C-字符串中的字符(或空字符)的數量加一為終止字符\\0

當將字符串文字作為例如 "Hello"傳遞給函數時,實際上傳遞了一個char[6] ,它將衰減為指針char* ,因為C ++不允許您按值傳遞數組。 此外,C ++ 不允許非const指針字符串文字,因此,參數類型必須成為const char*

級聯

std::string具有二進制加法運算符的現有重載,它允許您將兩個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 ++中從左到右執行添加,因此,長連接表達式需要以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

但是,你也可以完全跳過空格並使用單個字符串文字。

首先要理解的是,由於C語言中的祖先,C ++中的字符串文字"Hello"實際上並不是 string類型。 它的類型實際上是一個字符數組。

所以s3s4之間的區別在於,當你進行s3構造時,第一個操作是s1 + ", " s1是string類型,因此使用標准庫的字符串組件提供的+運算符,並返回一個要添加到"World!"的新字符串"World!"

現在對於s4 ,要執行的第一個操作是"Hello" + ", "或添加兩個字符串文字。 實際上,這個操作會被編譯器視為將兩個字符數組一起添加,這是一種語言不提供的功能,從而導致您看到的錯誤。

最簡單的解決方法是不要將+用於字符串文字,只需將它們放在同一個字符串中即可。 或者你可以從第一個文字創建一個string ,讓操作從那里開始工作( std::string("Hello") + ", " + s2

+運算符在std :: string中重載。 運算符重載應用於操作數,因此s1 + ...通過調用s1上的重載+運算符來工作。

文字"Hello"是一個const char * ,因此是"," const char *沒有重載+運算符,因此出錯。 嘗試string("Hello") + ...它會起作用。

感謝@interjay的修正

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM