Concatena due stringhe letterali


121

Sto leggendo Accelerated C ++ di Koenig. Scrive che "la nuova idea è che possiamo usare + per concatenare una stringa e una stringa letterale - o, se è per questo, due stringhe (ma non due stringhe letterali).

Bene, questo ha senso suppongo. Ora passiamo a due esercizi separati intesi a chiarire questo.

Le seguenti definizioni sono valide?

const string hello = "Hello";

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

Ora, ho provato a eseguire quanto sopra e ha funzionato! Quindi ero felice.

Poi ho provato a fare il prossimo esercizio;

const string exclam = "!";

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

Questo non ha funzionato. Ora capisco che abbia qualcosa a che fare con il fatto che non puoi concatenare due stringhe letterali, ma non capisco la differenza semantica tra il motivo per cui sono riuscito a far funzionare il primo esempio (non è ", world" e "! "due stringhe letterali? Non avrebbe dovuto funzionare?) ma non la seconda.


4
const string message = "Hello" ",world" + exclam(es. omettendo il primo +) dovrebbe funzionare bene.
n0

1
@ Joe - Perché qualcuno dovrebbe scrivere "Hello" + ", world!"quando puoi farlo "Hello, world!". Come al solito, il C ++ ha una soluzione fantastica e semplice per un problema percepito. :-)
Bo Persson

2
@Bo L'unica cosa a cui riesco a pensare è se usi una definizione (#define)
Joe Phillips

@ Joe Anche allora, è più probabile che tu scriva "Hello" ", world!"(senza il +). Ci sono una serie di lamentele che si potrebbero fare su C ++, ma non credo che la sua gestione qui sia una di queste. È esattamente la stessa cosa che se scrivessi 1 / 3 + 1.5e ti lamentassi perché la divisione era una divisione integrale. Nel bene e nel male, questo è il modo in cui funzionano la maggior parte delle lingue.
James Kanze

2
@Bo Persson In realtà questa funzione "hello" " world" == "hello world"è utile se devi scrivere una stringa lunga e non vuoi che esca dalla tua finestra o se vuoi essere all'interno di una limitazione della lunghezza della riga. O se una delle stringhe è definita in una macro.
Dimitar Slavchev

Risposte:


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

L' +operatore ha un'associatività da sinistra a destra, quindi l'espressione tra parentesi equivalente è:

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

Come puoi vedere, le due stringhe letterali "Hello"e ",world"vengono "aggiunte" per prime, da cui l'errore.

Una delle prime due stringhe da concatenare deve essere un std::stringoggetto:

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

In alternativa, puoi forzare la +valutazione del secondo per primo tra parentesi quella parte dell'espressione:

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

Ha senso che il tuo primo esempio ( hello + ",world" + "!") funzioni perché std::string( hello) è uno degli argomenti più a sinistra +. Che +viene valutato, il risultato è un std::stringoggetto con la stringa concatenata, e quello risultante std::stringviene poi concatenato con il "!".


Per quanto riguarda il motivo per cui non è possibile concatenare due stringhe letterali usando +, è perché una stringa letterale è solo un array di caratteri (a const char [N]dove Nè la lunghezza della stringa più uno, per il terminatore null). Quando si utilizza un array nella maggior parte dei contesti, viene convertito in un puntatore al suo elemento iniziale.

Quindi, quando provi a fare "Hello" + ",world", quello che stai veramente cercando di fare è aggiungere due const char*s insieme, il che non è possibile (cosa significherebbe aggiungere due puntatori insieme?) E se lo fosse non farebbe quello che tu voleva che lo facesse.


Notare che è possibile concatenare i valori letterali stringa posizionandoli uno accanto all'altro; ad esempio, i due seguenti sono equivalenti:

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

Ciò è utile se si dispone di una stringa letterale lunga che si desidera suddividere su più righe. Devono essere stringhe letterali, però: questo non funzionerà con i const char*puntatori o gli const char[N]array.


3
Inoltre, const string message = "Hello" + (",world"+exclam);funzionerà anche a causa della parentesi esplicita (è una parola?).
Chinmay Kanchi

1
Potrebbe essere ancora più completo se indichi perché il primo esempio funziona:const string message = ((hello + ",world") + "!");
Mark Ransom

Grazie! Sospettavo che avesse qualcosa a che fare con l'associatività da sinistra a destra, ma non ne ero sicuro e questa differenza semantica non aveva molto senso per me. Apprezzo la risposta!
Arthur Collé

2
Direi che la "Hello" ",world"sintassi è utile non solo per suddividere in più righe, ma anche quando uno dei valori letterali di stringa è una macro (o anche entrambi). Quindi la concatenazione avviene in fase di compilazione.
Melebius

8

Dovresti sempre prestare attenzione ai tipi .

Anche se sembrano tutti stringhe "Hello"e ",world"sono letterali .

E nel tuo esempio, exclamè un std::stringoggetto.

C ++ ha un sovraccarico di operatori che accetta un std::stringoggetto e vi aggiunge un'altra stringa. Quando concatenate un std::stringoggetto con un letterale, verrà eseguita la fusione appropriata per il letterale.

Ma se provi a concatenare due letterali, il compilatore non sarà in grado di trovare un operatore che accetta due letterali.


Vedere std :: operator + che offre overload per concatenare un std::stringcon un altro std::string, un array di caratteri o un singolo carattere.
DavidRR

7

Il secondo esempio non funziona perché non esistono operator +due stringhe letterali. Notare che una stringa letterale non è di tipo string, ma è invece di tipo const char *. Il tuo secondo esempio funzionerà se lo rivedi in questo modo:

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

4

A partire da C ++ 14 puoi usare due stringhe letterali reali :

const string hello = "Hello"s;

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

o

const string exclam = "!"s;

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

2

Nel caso 1, a causa dell'ordine delle operazioni ottieni:

(ciao + ", mondo") + "!" che si risolve in ciao + "!" e infine un saluto

Nel caso 2, come ha notato James, ottieni:

("Hello" + ", world") + esclam che è il concatenamento di 2 stringhe letterali.

Spero sia chiaro :)


1

La differenza tra una stringa (o per essere precisi std::string) e un carattere letterale è che per quest'ultimo non è +definito alcun operatore. Questo è il motivo per cui il secondo esempio fallisce.

Nel primo caso, il compilatore può trovare un adatto operator+con il primo argomento a stringe il secondo un carattere letterale ( const char*), quindi lo usa. Il risultato di quell'operazione è di nuovo a string, quindi ripete lo stesso trucco quando viene aggiunto "!".

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.