web-dev-qa-db-fra.com

Concaténer deux littéraux de chaîne

Je lis le C++ accéléré par Koenig. Il écrit que "la nouvelle idée est que nous pouvons utiliser + pour concaténer une chaîne et un littéral de chaîne - ou même deux chaînes (mais pas deux littéraux de chaîne).

Bien, cela a du sens, je suppose. Passons maintenant à deux exercices distincts destinés à éclairer ceci.

Les définitions suivantes sont-elles valides?

const string hello = "Hello";

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

Maintenant, j'ai essayé d'exécuter ce qui précède et cela a fonctionné! Donc j'étais heureux.

Ensuite, j'ai essayé de faire le prochain exercice.

const string exclam = "!";

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

Cela n'a pas fonctionné. Maintenant, je comprends que cela a quelque chose à voir avec le fait que vous ne pouvez pas concaténer deux littéraux de chaîne, mais je ne comprends pas la différence sémantique entre la raison pour laquelle j'ai réussi à obtenir le premier exemple (non pas ", monde" et "! "deux littéraux de chaîne? Cela n'aurait-il pas dû fonctionner?) mais pas la seconde.

115
Arthur Collé
const string message = "Hello" + ",world" + exclam;

L'opérateur + A une associativité de gauche à droite; l'expression entre parenthèses équivalente est la suivante:

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

Comme vous pouvez le constater, les deux littéraux de chaîne "Hello" Et ",world" Sont "ajoutés" en premier, d'où l'erreur.

Une des deux premières chaînes à concaténer doit être un objet std::string:

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

Vous pouvez également forcer le second + À être évalué en premier en mettant entre parenthèses cette partie de l'expression:

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

Il est logique que votre premier exemple (hello + ",world" + "!") Fonctionne, car le std::string (hello) est l’un des arguments le plus à gauche +. Que + Soit évalué, le résultat est un objet std::string Avec la chaîne concaténée et le résultat std::string Résultant est ensuite concaténé avec le "!".


Quant à pourquoi vous ne pouvez pas concaténer deux littéraux de chaîne en utilisant +, C’est parce qu’un littéral de chaîne est juste un tableau de caractères (un const char [N]N est la longueur de la chaîne plus un, pour le terminateur nul). Lorsque vous utilisez un tableau dans la plupart des contextes, il est converti en un pointeur sur son élément initial.

Donc, lorsque vous essayez de faire "Hello" + ",world", Ce que vous essayez réellement de faire est d’ajouter deux const char* Ensemble, ce qui n’est pas possible (que signifierait-on ajouter deux pointeurs ensemble? ) et si c’était le cas, il ne ferait pas ce que vous vouliez.


Notez que vous can concaténez des littéraux de chaîne en les plaçant l'un à côté de l'autre; par exemple, les deux suivants sont équivalents:

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

Ceci est utile si vous avez un long littéral que vous voulez diviser en plusieurs lignes. Ils doivent cependant être des littéraux de chaîne: cela ne fonctionnera pas avec les pointeurs const char* Ou les tableaux const char[N].

132
James McNellis

Vous devriez toujours faire attention à types.

Bien qu'ils ressemblent tous à des chaînes, "Hello" et ",world" sont littéraux.

Et dans votre exemple, exclam est un std::string objet.

C++ a une surcharge d'opérateur qui prend un std::string objet et y ajoute une autre chaîne. Lorsque vous concaténez un std::string objet avec un littéral, il fera le casting approprié pour le littéral.

Mais si vous essayez de concaténer deux littéraux, le compilateur ne pourra pas trouver un opérateur prenant deux littéraux.

8
Yochai Timmer

Votre deuxième exemple ne fonctionne pas car il n'y a pas de operator + pour deux littéraux de chaîne. Notez qu'un littéral de chaîne n'est pas de type string, mais de type const char *. Votre deuxième exemple fonctionnera si vous le révisez comme ceci:

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

Dans le cas 1, en raison de l'ordre des opérations, vous obtenez:

(bonjour + "monde") + "!" qui résout bonjour + "!" et enfin bonjour

Dans le cas 2, comme l'a noté James, vous obtenez:

("Hello" + ", world") + exclam qui est le concat de 2 littéraux de chaîne.

J'espère que c'est clair :)

2
Stephen

La différence entre une chaîne (ou plus précisément, std::string) et un caractère littéral est que pour ce dernier il n'y a pas de + opérateur défini. C'est pourquoi le deuxième exemple échoue.

Dans le premier cas, le compilateur peut trouver un operator+ avec le premier argument étant un string et le second un caractère littéral (const char*) donc il a utilisé ça. Le résultat de cette opération est à nouveau un string, de sorte qu'il répète le même truc lors de l'ajout de "!" à elle.

1
Péter Török