Verketten Sie zwei String-Literale

121

Ich lese Accelerated C ++ von Koenig. Er schreibt: "Die neue Idee ist, dass wir + verwenden können, um einen String und ein String-Literal zu verketten - oder zwei Strings (aber nicht zwei String-Literale).

Gut, das macht wohl Sinn. Nun zu zwei getrennten Übungen, die dies beleuchten sollen.

Sind die folgenden Definitionen gültig?

const string hello = "Hello";

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

Jetzt habe ich versucht, das oben genannte auszuführen und es hat funktioniert! Also war ich glücklich.

Dann versuchte ich die nächste Übung zu machen;

const string exclam = "!";

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

Das hat nicht funktioniert. Jetzt verstehe ich, dass es etwas damit zu tun hat, dass Sie nicht zwei String-Literale verketten können, aber ich verstehe den semantischen Unterschied nicht, warum ich es geschafft habe, das erste Beispiel zum Laufen zu bringen (ist nicht ", world" und "! "zwei String-Literale? Sollte das nicht funktioniert haben?), aber nicht das zweite.

Arthur Collé
quelle
4
const string message = "Hello" ",world" + exclam(zB das erste weglassen +) sollte gut funktionieren.
n0rd
1
@ Joe - Warum sollte jemand schreiben, "Hello" + ", world!"wenn Sie können "Hello, world!". Wie üblich bietet C ++ eine fantastische und einfache Problemumgehung für ein wahrgenommenes Problem. :-)
Bo Persson
2
@ Bo Das einzige, woran ich denken kann, ist, wenn Sie eine Definition (#define) verwenden
Joe Phillips
@ Joe Selbst dann schreibst du eher "Hello" ", world!"(ohne das +). Es gibt eine Reihe von Beschwerden, die man über C ++ machen könnte, aber ich denke nicht, dass die Behandlung hier eine davon ist. Es ist genau das Gleiche, als ob Sie geschrieben 1 / 3 + 1.5und sich beschwert hätten, weil die Teilung eine integrale Teilung war. Zum Guten oder zum Schlechten funktionieren die meisten Sprachen so.
James Kanze
2
@Bo Persson Eigentlich ist diese Funktion "hello" " world" == "hello world"nützlich, wenn Sie eine lange Zeichenfolge schreiben müssen und nicht möchten, dass sie aus Ihrem Fenster verschwindet, oder wenn Sie sich innerhalb einer Zeilenlängenbeschränkung befinden möchten. Oder wenn eine der Zeichenfolgen in einem Makro definiert ist.
Dimitar Slavchev

Antworten:

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

Der +Operator hat eine Assoziativität von links nach rechts, daher lautet der entsprechende Ausdruck in Klammern:

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

Wie Sie sehen können, werden die beiden Zeichenfolgenliterale "Hello"und zuerst ",world""hinzugefügt", daher der Fehler.

Eine der ersten beiden verketteten Zeichenfolgen muss ein std::stringObjekt sein:

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

Alternativ können Sie erzwingen, dass die zweite +zuerst ausgewertet wird, indem Sie diesen Teil des Ausdrucks in Klammern setzen:

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

Es ist sinnvoll, dass Ihr erstes Beispiel ( hello + ",world" + "!") funktioniert, da std::string( hello) eines der Argumente ganz links ist +. Das +heißt, das Ergebnis ist ein std::stringObjekt mit der verketteten Zeichenfolge, und das Ergebnis std::stringwird dann mit der verketteten Zeichenfolge verkettet "!".


Der Grund , warum Sie zwei Zeichenfolgenliterale nicht mit verketten können +, liegt daran, dass ein Zeichenfolgenliteral nur ein Array von Zeichen ist (a const char [N]wobei Ndie Länge der Zeichenfolge plus eins für den Nullterminator ist). Wenn Sie ein Array in den meisten Kontexten verwenden, wird es in einen Zeiger auf sein Anfangselement konvertiert.

Wenn Sie also versuchen, "Hello" + ",world"zwei const char*s zusammen zu addieren , was nicht möglich ist (was würde es bedeuten, zwei Zeiger zusammen zu addieren?), Und wenn dies der Fall wäre, würde es nicht das tun, was Sie tun wollte es tun.


Beachten Sie, dass Sie Zeichenfolgenliterale verketten können, indem Sie sie nebeneinander platzieren. Die folgenden beiden sind beispielsweise gleichwertig:

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

Dies ist nützlich, wenn Sie ein langes Zeichenfolgenliteral haben, das Sie in mehrere Zeilen aufteilen möchten. Es müssen jedoch Zeichenfolgenliterale sein: Dies funktioniert nicht mit const char*Zeigern oder const char[N]Arrays.

James McNellis
quelle
3
Funktioniert auch const string message = "Hello" + (",world"+exclam);aufgrund der expliziten Klammerung (ist das ein Wort?).
Chinmay Kanchi
1
Könnte noch vollständiger sein, wenn Sie darauf hinweisen, warum das erste Beispiel funktioniert:const string message = ((hello + ",world") + "!");
Mark Ransom
Danke dir! Ich vermutete, dass es etwas mit der Assoziativität von links nach rechts zu tun hatte, war mir aber nicht sicher und dieser semantische Unterschied ergab für mich keinen Sinn. Ich schätze die Antwort!
Arthur Collé
2
Ich würde erwähnen, dass die "Hello" ",world"Syntax nicht nur zum Aufteilen in mehrere Zeilen nützlich ist, sondern auch, wenn eines der Zeichenfolgenliterale ein Makro ist (oder sogar beide). Dann erfolgt die Verkettung in der Kompilierungszeit.
Melebius
8

Sie sollten immer auf Typen achten .

Obwohl sie alle scheinen wie Saiten, "Hello"und ",world"sind Literale .

Und in Ihrem Beispiel exclamist ein std::stringObjekt.

C ++ hat eine Operatorüberladung, die ein std::stringObjekt nimmt und ihm eine weitere Zeichenfolge hinzufügt. Wenn Sie ein std::stringObjekt mit einem Literal verketten , wird das entsprechende Casting für das Literal vorgenommen.

Wenn Sie jedoch versuchen, zwei Literale zu verketten, kann der Compiler keinen Operator finden, der zwei Literale verwendet.

Yochai Timmer
quelle
Siehe std :: operator +, der Überladungen zum Verketten von a std::stringmit einem anderen std::string, einem Zeichenarray oder einem einzelnen Zeichen bietet .
DavidRR
7

Ihr zweites Beispiel funktioniert nicht, da es operator +für zwei Zeichenfolgenliterale kein Nein gibt . Beachten Sie, dass ein Zeichenfolgenliteral nicht vom Typ string, sondern vom Typ ist const char *. Ihr zweites Beispiel funktioniert, wenn Sie es folgendermaßen überarbeiten:

const string message = string("Hello") + ",world" + exclam;
Juraj Blaho
quelle
4

Seit C ++ 14 können Sie zwei echte String-Literale verwenden :

const string hello = "Hello"s;

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

oder

const string exclam = "!"s;

const string message = "Hello"s + ",world"s + exclam;
Thomas Sablik
quelle
2

In Fall 1 erhalten Sie aufgrund der Reihenfolge der Operationen:

(Hallo + ", Welt") + "!" was zu hallo + "!" und schließlich zu hallo

In Fall 2 erhalten Sie, wie James bemerkte, Folgendes:

("Hallo" + ", Welt") + exclam, das ist das Concat von 2 String-Literalen.

Hoffe es ist klar :)

Stephen
quelle
1

Der Unterschied zwischen einer Zeichenfolge (oder genauer gesagt std::string) und einem Zeichenliteral besteht darin, dass für letzteres kein +Operator definiert ist. Aus diesem Grund schlägt das zweite Beispiel fehl.

Im ersten Fall kann der Compiler ein geeignetes finden, operator+wobei das erste Argument a stringund das zweite ein Zeichenliteral ( const char*) ist, also hat er das verwendet. Das Ergebnis dieser Operation ist wieder a string, daher wird derselbe Trick beim Hinzufügen wiederholt "!".

Péter Török
quelle