Je lis Accelerated C ++ par Koenig. Il écrit que «la nouvelle idée est que nous pouvons utiliser + pour concaténer une chaîne et une chaîne littérale - ou, d'ailleurs, deux chaînes (mais pas deux chaînes littérales).
Bien, cela a du sens, je suppose. Passons maintenant à deux exercices distincts destinés à éclairer cela.
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é! Alors j'étais content.
Ensuite, j'ai essayé de faire l'exercice suivant;
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 chaînes littérales, mais je ne comprends pas la différence sémantique entre pourquoi j'ai réussi à faire fonctionner le premier exemple (n'est pas ", world" et "! "deux chaînes littérales? Cela n'aurait-il pas dû fonctionner?) mais pas le second.
const string message = "Hello" ",world" + exclam
(par exemple en omettant le premier+
) devrait fonctionner très bien."Hello" + ", world!"
alors que vous pouvez le faire"Hello, world!"
. Comme d'habitude, C ++ a une solution de contournement impressionnante et simple pour un problème perçu. :-)"Hello" ", world!"
(sans le+
). Il y a un certain nombre de plaintes que l'on pourrait faire à propos du C ++, mais je ne pense pas que sa gestion ici en soit une. C'est exactement la même chose que si vous écriviez1 / 3 + 1.5
et que vous vous plaigniez parce que la division était une division intégrale. Pour le meilleur ou pour le pire, c'est ainsi que fonctionnent la plupart des langues."hello" " world" == "hello world"
est utile si vous devez écrire une longue chaîne et que vous ne voulez pas qu'elle sorte de votre fenêtre ou que vous voulez être dans une certaine restriction de longueur de ligne. Ou si l'une des chaînes est définie dans une macro.Réponses:
L'
+
opérateur a une associativité de gauche à droite, donc l'expression équivalente entre parenthèses est:Comme vous pouvez le voir, les deux chaînes littérales
"Hello"
et",world"
sont «ajoutées» en premier, d'où l'erreur.L'une des deux premières chaînes concaténées doit être un
std::string
objet:Vous pouvez également forcer le second
+
à être évalué en premier en mettant entre parenthèses cette partie de l'expression:Il est logique que votre premier exemple (
hello + ",world" + "!"
) fonctionne car lestd::string
(hello
) est l'un des arguments à l'extrême gauche+
. Cela+
est évalué, le résultat est unstd::string
objet avec la chaîne concaténée, et ce résultatstd::string
est ensuite concaténé avec le"!"
.Quant à savoir pourquoi vous ne pouvez pas concaténer deux chaînes littérales en utilisant
+
, c'est parce qu'une chaîne littérale est juste un tableau de caractères (const char [N]
où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 vers son élément initial.Donc, quand vous essayez de faire
"Hello" + ",world"
, ce que vous essayez vraiment de faire est d'ajouter deuxconst char*
s ensemble, ce qui n'est pas possible (qu'est-ce que cela signifierait d'ajouter deux pointeurs ensemble?) Et si c'était le cas, cela ne ferait pas ce que vous voulait qu'il le fasse.Notez que vous pouvez concaténer des chaînes littérales en les plaçant les unes à côté des autres; par exemple, les deux suivants sont équivalents:
Ceci est utile si vous avez une longue chaîne littérale que vous souhaitez diviser en plusieurs lignes. Ils doivent cependant être des chaînes littérales: cela ne fonctionnera pas avec des
const char*
pointeurs ou desconst char[N]
tableaux.la source
const string message = "Hello" + (",world"+exclam);
cela fonctionnera aussi, à cause de la parenthèse explicite (est-ce un mot?).const string message = ((hello + ",world") + "!");
"Hello" ",world"
syntaxe est utile non seulement pour diviser en plusieurs lignes, mais également lorsque l'un des littéraux de chaîne est une macro (ou même les deux). Ensuite, la concaténation se produit au moment de la compilation.Vous devez toujours faire attention aux types .
Bien qu'ils ressemblent tous à des chaînes,
"Hello"
et qu'ils",world"
soient littéraux .Et dans votre exemple,
exclam
est unstd::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 unstd::string
objet avec un littéral, il effectuera le cast approprié pour le littéral.Mais si vous essayez de concaténer deux littéraux, le compilateur ne pourra pas trouver un opérateur qui prend deux littéraux.
la source
std::string
avec un autrestd::string
, un tableau de caractères ou un seul caractère.Votre deuxième exemple ne fonctionne pas car il n'y a pas
operator +
pour deux chaînes littérales. Notez qu'un littéral de chaîne n'est pas de typestring
, mais plutôt de typeconst char *
. Votre deuxième exemple fonctionnera si vous le révisez comme ceci:la source
Depuis C ++ 14, vous pouvez utiliser deux littéraux de chaîne réels :
ou
la source
Dans le cas 1, en raison de l'ordre des opérations, vous obtenez:
(bonjour + ", monde") + "!" qui se résout en bonjour + "!" et enfin bonjour
Dans le cas 2, comme James l'a noté, vous obtenez:
("Hello" + ", world") + exclam qui est le concat de 2 chaînes littérales.
J'espère que c'est clair :)
la source
La différence entre une chaîne (ou pour être précis
std::string
) et un littéral de caractère est que pour ce dernier, aucun+
opérateur n'est défini. C'est pourquoi le deuxième exemple échoue.Dans le premier cas, le compilateur peut trouver un convenable
operator+
avec le premier argument étant astring
et le second un caractère littéral (const char*
) donc il l'a utilisé. Le résultat de cette opération est à nouveau unstring
, donc il répète la même astuce lors de l'ajout"!"
.la source