[英]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
應該這樣做。
為什么我會收到這個錯誤? 這兩個初始化字符串( s3
和s4
)之間有什么區別?
"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 ++中,字符串通常表示為任一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
類型。 它的類型實際上是一個字符數組。
所以s3
和s4
之間的區別在於,當你進行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.