web-dev-qa-db-fra.com

Quelle est la justification de la parenthèse dans les littéraux de chaîne bruts R "(...)" de C ++ 11?

Il existe une fonctionnalité très pratique introduite en C++ 11 appelée littéraux de chaîne bruts, qui sont des chaînes sans caractères d'échappement. Et au lieu d'écrire ceci:

  regex mask("\\t[0-9]+\\.[0-9]+\\t\\\\SUB");

Vous pouvez simplement écrire ceci:

  regex mask(R"(\t[0-9]+\.[0-9]+\t\\SUB)");

Beaucoup plus lisible. Cependant, notez les parenthèses supplémentaires autour de la chaîne que vous devez placer pour définir un littéral de chaîne brut.

Ma question est, pourquoi en avons-nous même besoin? Pour moi, cela semble assez laid et illogique. Voici les inconvénients de ce que je vois:

  • Plus de verbosité, tandis que toute la fonctionnalité est utilisée pour rendre les littéraux plus compacts
  • Difficile de distinguer entre le corps du littéral et les symboles qui définissent

C'est ce que je veux dire par la distinction difficile:

"good old usual string literal"
 ^-    body inside quotes   -^

R"(new strange raw string literal)"
   ^- body inside parenthesis  -^

Et voici le pro:

  • Plus de flexibilité, plus de caractères disponibles dans les chaînes brutes, en particulier lorsqu'ils sont utilisés avec le délimiteur: "delim( can use "()" here )delim"

Mais bon, si vous avez besoin de plus de flexibilité, vous avez de bons vieux littéraux de chaîne échappables. Pourquoi le comité standard a décidé de polluer le contenu de chaque chaîne littérale brute avec ces parenthèses absolument inutiles? Quelle était la raison derrière cela? Quels sont les avantages que je n'ai pas mentionnés?

UPD La réponse de Kerrek est excellente, mais ce n'est malheureusement pas une réponse. Comme je l'ai déjà décrit, je comprends comment cela fonctionne et quels avantages cela apporte. Cinq ans se sont écoulés depuis que j'ai posé cette question, et il n'y a toujours pas de réponse. Et je suis toujours frustré par cette décision. On pourrait dire que c'est une question de goût, mais je ne suis pas d'accord. Combien d'espaces utilisez-vous, comment nommez-vous vos variables, est-ce SomeFunction() ou some_function() - c'est une question de goût. Et je peux vraiment facilement passer d'un style à un autre.

Mais cela? .. Se sent toujours maladroit et maladroit après tant d'années. Non, ce n'est pas une question de goût. Il s'agit de savoir comment nous voulons couvrir tous les cas possibles, quoi qu'il arrive. Nous sommes voués à écrire ces parens laids chaque fois que nous avons besoin d'écrire un chemin d'accès spécifique à Windows, ou une expression régulière, ou un littéral de chaîne multiligne. Et pour quoi? .. Pour ces rares cas où nous devons réellement mettre " Dans une chaîne? J'aimerais bien être à cette réunion du comité où ils ont décidé de le faire de cette façon. Et je serais fortement contre cette très mauvaise décision. Je souhaite que. Maintenant, nous sommes condamnés.

Merci d'avoir lu jusqu'ici. Maintenant je me sens un peu mieux.

PD2 Voici mes propositions alternatives, qui je pense que les deux seraient BEAUCOUP mieux qu'existantes.

Proposition 1. Inspiré par python. Impossible de prendre en charge les littéraux de chaîne avec des guillemets triples: R"""Here is a string literal with any content, except for triple quotes, which you don't actually use that often."""

Proposition 2. Inspirée par le bon sens. Prend en charge tous les littéraux de chaîne possibles, tout comme l'actuel: R"delim"content of string"delim". Avec un délimiteur vide: R""Looks better, doesn't it?"". Chaîne brute vide: R"""". Chaîne brute avec guillemets doubles: R"#"Here are double quotes: "", thanks"#".

Des problèmes avec ces propositions?

67
Mikhail

Comme l'explique l'autre réponse, il doit y avoir quelque chose de plus que le guillemet pour éviter l'ambiguïté d'analyse dans les cas où " ou )", ou en fait n'importe quelle séquence de fermeture qui peut apparaître dans la chaîne elle-même.

Quant au choix de la syntaxe, eh bien, je suis d'accord que le choix de la syntaxe est sous-optimal , mais c'est OK en général (vous pourriez penser: "les choses pourraient être pire ", lol). Je pense que c'est un bon compromis entre la simplicité d'utilisation et la simplicité d'analyse.

Proposition 1. Inspiré du python. Impossible de prendre en charge les littéraux de chaîne avec des guillemets triples:
R "" "tout contenu, à l'exception des guillemets triples, que vous n'utilisez pas souvent." ""

Il y a en effet un problème avec cela - "les guillemets, que vous n'utilisez pas vraiment souvent". Tout d'abord, l'idée même des chaînes brutes est de représenter des chaînes brutes , c'est-à-dire exactement comme elles apparaîtront dans un fichier texte, sans toute modification de la chaîne, quel que soit son contenu. Deuxièmement, la syntaxe doit être générale, c'est-à-dire sans ajouter de variations comme "chaîne presque brute", etc.

Comment écririez-vous une citation avec cette syntaxe? Deux citations? Remarque - ce sont des cas très courants, en particulier lorsque votre code traite des chaînes et de l'analyse.

Proposition 2.
R "delim" contenu de la chaîne "delim".
R "" Ça a l'air mieux, n'est-ce pas? "".
R "#" Voici des guillemets doubles: "", merci "#".

Eh bien, celui-ci pourrait être un meilleur candidat. Une chose cependant - un cas courant (et je crois que c'était un cas motivant pour la syntaxe acceptée), est que le caractère entre guillemets lui-même est très commun et les chaînes brutes devraient être utiles pour ces cas.

Donc, voyons, syntaxe de chaîne normale:

s1 = "\"";
s2 = "\"quoted string\"";

Votre syntaxe, par exemple avec "x" comme délimiteur:

s1 = R"x"""x";
s2 = R"x""quoted string""x";

Syntaxe acceptée:

s1 = R"(")";
s2 = R"("quoted string")";

Oui, je suis d'accord que les crochets introduisent un effet visuel gênant. Je soupçonne donc que les auteurs de la syntaxe recherchaient l'idée que le "délimiteur" supplémentaire dans ce cas sera rarement nécessaire, car )" n'apparaît pas très souvent dans une chaîne. Mais OTOH, les guillemets de fin/principaux/isolés sont assez souvent, par exemple la syntaxe que vous proposez (# 2) nécessiterait plus de delim plus souvent, ce qui nécessiterait à son tour de la changer plus souvent de R"".."" à R"delim"..."delim". J'espère que vous aurez l'idée.

La syntaxe pourrait-elle être meilleure? Personnellement, je préférerais une variante encore plus simple de la syntaxe:

Rdelim"string contents"delim;

Avec les exemples ci-dessus:

s1 = Rx"""x; 
s2 = Rx""quoted string""x;

Cependant, pour fonctionner correctement (si cela est possible dans la grammaire actuelle), cette variante nécessiterait de limiter le jeu de caractères pour la partie delim, disons uniquement aux lettres/chiffres (en raison des opérateurs existants), et peut-être un peu plus loin. restrictions pour le caractère initial pour éviter les conflits avec une future grammaire possible.
Je pense donc qu'un meilleur choix aurait pu être fait, bien que rien significatif mieux ne puisse être fait dans ce cas.

5
Mikhail V

Le but des parenthèses est de vous permettre de spécifier un délimiteur personnalisé:

R"foo(Hello World)foo"   // the string "Hello World"

Dans votre exemple, et dans une utilisation typique, le délimiteur est simplement vide, donc la chaîne brute est entourée par les séquences R"( Et )".

Permettre des délimiteurs arbitraires est une décision de conception qui reflète le désir de fournir une solution complète sans limitations étranges ou cas Edge. Vous pouvez choisir tout séquence de caractères qui ne se produit pas dans votre chaîne comme délimiteur.

Sans cela, vous auriez des problèmes si la chaîne elle-même contenait quelque chose comme " (Si vous vouliez juste R"..." Comme syntaxe de chaîne brute) ou )" (Si le délimiteur est vide). Les deux sont des séquences de caractères parfaitement communes et fréquentes, en particulier dans les expressions régulières, il serait donc extrêmement ennuyeux si la décision d'utiliser ou non une chaîne brute dépendait du contenu spécifique de votre chaîne.

N'oubliez pas qu'à l'intérieur de la chaîne brute, il n'y a pas d'autre mécanisme d'échappement, donc le mieux que vous puissiez faire autrement serait de concaténer des morceaux de chaîne littérale, ce qui serait très peu pratique. En autorisant un délimiteur personnalisé, tout ce que vous avez à faire est de sélectionner une séquence de caractères inhabituelle une fois, et peut-être de la modifier dans de très rares cas lorsque vous effectuez une future modification.

Mais pour souligner encore une fois, même le délimiteur vide est déjà utile, car la syntaxe R"(...)" vous permet de placer des guillemets nus dans votre chaîne. En soi, c'est tout à fait un gain.

95
Kerrek SB