Was ist der Grund für die Klammer in C ++ 11s rohen String-Literalen R „(…)“?

74

In C ++ 11 wurde eine sehr praktische Funktion eingeführt, die als Raw-String-Literale bezeichnet wird. Hierbei handelt es sich um Strings ohne Escape-Zeichen. Und anstatt dies zu schreiben:

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

Sie können dies einfach schreiben:

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

Ziemlich lesbarer. Beachten Sie jedoch zusätzliche Klammern um die Zeichenfolge, die platziert werden müssen, um ein rohes Zeichenfolgenliteral zu definieren.

Meine Frage ist, warum brauchen wir diese überhaupt? Für mich sieht es ziemlich hässlich und unlogisch aus. Hier sind die Nachteile, die ich sehe:

  • Zusätzliche Ausführlichkeit, während die gesamte Funktion verwendet wird, um Literale kompakter zu gestalten
  • Schwer zu unterscheiden zwischen dem Körper des Literal und den definierenden Symbolen

Das meine ich mit der harten Unterscheidung:

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

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

Und hier ist der Profi:

  • Mehr Flexibilität, mehr Zeichen in rohen Zeichenfolgen verfügbar, insbesondere bei Verwendung mit dem Trennzeichen: "delim( can use "()" here )delim"

Aber hey, wenn Sie mehr Flexibilität benötigen, haben Sie alte, gute, flüchtige String-Literale. Warum hat das Standardkomitee beschlossen, den Inhalt jedes rohen String-Literals mit diesen absolut unnötigen Klammern zu verschmutzen? Was war der Grund dafür? Was sind die Profis, die ich nicht erwähnt habe?

UPD Die Antwort von Kerrek ist großartig, aber leider keine Antwort. Da ich bereits beschrieben habe, dass ich verstehe, wie es funktioniert und welche Vorteile es bietet. Fünf Jahre sind vergangen, seit ich diese Frage gestellt habe, und es gibt immer noch keine Antwort. Und diese Entscheidung frustriert mich immer noch. Man könnte sagen, dass dies Geschmackssache ist, aber ich würde nicht zustimmen. Wie viele Leerzeichen verwenden Sie, wie benennen Sie Ihre Variablen, ist dies SomeFunction()oder some_function()- das ist Geschmackssache. Und ich kann wirklich leicht von einem Stil zum anderen wechseln.

Aber das? .. fühlt sich nach so vielen Jahren immer noch unbeholfen und ungeschickt an. Nein, hier geht es nicht um den Geschmack. Hier geht es darum, wie wir alle möglichen Fälle abdecken wollen, egal was passiert. Wir waren dazu verdammt, diese hässlichen Parens jedes Mal zu schreiben, wenn wir einen Windows-spezifischen Pfad, einen regulären Ausdruck oder ein mehrzeiliges String-Literal schreiben müssen. Und wofür? .. Für die seltenen Fälle, in denen wir tatsächlich "eine Zeichenfolge einfügen müssen? Ich wünschte, ich wäre auf dieser Ausschusssitzung, wo sie beschlossen hätten, dies auf diese Weise zu tun. Und ich wäre stark gegen diese wirklich schlechte Entscheidung. Ich wünsche. Jetzt sind wir zum Scheitern verurteilt.

Vielen Dank, dass Sie so weit gelesen haben. Jetzt geht es mir etwas besser.

UPD2 Hier sind meine alternativen Vorschläge, von denen ich denke, dass beide VIEL besser wären als die bestehenden.

Vorschlag 1. Inspiriert von Python. String-Literale mit dreifachen Anführungszeichen können nicht unterstützt werden:R"""Here is a string literal with any content, except for triple quotes, which you don't actually use that often."""

Vorschlag 2. Inspiriert vom gesunden Menschenverstand. Unterstützt alle möglichen String-Literale, genau wie das aktuelle : R"delim"content of string"delim". Mit leerem Trennzeichen : R""Looks better, doesn't it?"". Leere Rohzeichenfolge : R"""". Rohzeichenfolge mit doppelten Anführungszeichen : R"#"Here are double quotes: "", thanks"#".

Probleme mit diesen Vorschlägen?

Mikhail
quelle
13
R";-](R"(this is a basic raw string literal as text inside a more complex one)");-]"
Pepper_chico
Die Syntax ist zwar ziemlich hässlich, aber ich kann mir keine Alternative vorstellen, die auch abwärtskompatibel bleibt und alle Funktionen beibehält.
ChilliDoughnuts
@ChilliDoughnuts, siehe die aktualisierte Frage.
Mikhail
1
@Mikhail: " Für die seltenen Fälle, in denen wir tatsächlich" in eine Zeichenfolge setzen müssen? "Die Tatsache, dass Sie glauben, dass Fälle, in denen Sie "eine rohe Zeichenfolge benötigen, " selten "sind, ist wahrscheinlich Teil des Problems. Es ist nicht so, dass es" keine Antwort "gibt. Es gibt eine Antwort; Sie stimmen einfach nicht damit überein . Wenn Ihre Definition dessen, was eine "Antwort" darstellt, "etwas ist, das mich überzeugt, meine Meinung dazu zu ändern", dann ist Ihre Frage zu eigensinnig. Die Begründung wurde geliefert, Ihre Zustimmung dazu ist nicht erforderlich.
Nicol Bolas
1
Sie sollten eine historisch hoch bewertete Frage nicht aktualisieren, um eine neue Frage aufzunehmen. Stellen Sie stattdessen eine neue Frage. (Was wahrscheinlich sowieso als meinungsbasiert geschlossen wird, da Ihr einziger Einwand "Ich finde das unästhetisch" zu sein scheint)
MM

Antworten:

8

Wie die andere Antwort erklärt, muss das Anführungszeichen zusätzlich hinzugefügt werden, um die Mehrdeutigkeit beim Parsen in Fällen zu vermeiden, in denen "oder )"oder tatsächlich eine Abschlusssequenz in der Zeichenfolge selbst erscheint.

Was die Syntaxauswahl betrifft, stimme ich zu, dass die Syntaxauswahl suboptimal ist , aber im Allgemeinen in Ordnung ist (man könnte sich vorstellen: "Dinge könnten schlimmer sein", lol). Ich denke, es ist ein guter Kompromiss zwischen einfacher Verwendung und einfacher Analyse.

Vorschlag 1 . Inspiriert von Python. String-Literale mit dreifachen Anführungszeichen können nicht unterstützt werden:
R "" "Inhalte, mit Ausnahme von dreifachen Anführungszeichen, die Sie nicht so oft verwenden." ""

Es gibt in der Tat ein Problem damit - "Anführungszeichen, die Sie eigentlich nicht so oft verwenden". Zum einen ist die Idee der rohen Strings darzustellen rohe Strings, also genau so , wie sie in einer Textdatei, ohne erscheinen würde jegliche Änderungen an der Zeichenfolge, unabhängig von den String Inhalt. Zweitens sollte die Syntax allgemein sein, dh ohne Variationen wie "fast rohe Zeichenfolge" usw. hinzuzufügen.

Wie würden Sie ein Zitat mit dieser Syntax schreiben? Zwei Zitate? Hinweis - Dies sind sehr häufige Fälle, insbesondere wenn sich Ihr Code mit Zeichenfolgen und Parsing befasst.

Vorschlag 2 .
R "delim" Inhalt der Zeichenfolge "delim".
R "" Sieht besser aus, nicht wahr? "".
R "#" Hier sind doppelte Anführungszeichen: "", danke "#".

Nun, dieser könnte ein besserer Kandidat sein. Eine Sache - ein häufiger Fall (und ich glaube, es war ein motivierender Fall für akzeptierte Syntax) - ist, dass das doppelte Anführungszeichen selbst sehr häufig ist und rohe Zeichenfolgen für diese Fälle nützlich sein sollten.

Mal sehen, normale String-Syntax:

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

Ihre Syntax zB mit "x" als Delim:

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

Akzeptierte Syntax:

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

Ja, ich stimme zu, dass die Klammern einen störenden visuellen Effekt hervorrufen. Ich vermute also, dass die Autoren der Syntax nach der Idee waren, dass das zusätzliche "Delim" in diesem Fall selten benötigt wird, da es )"nicht sehr oft in einem String vorkommt. Aber OTOH, nachgestellte / führende / isolierte Anführungszeichen sind ziemlich häufig, so dass beispielsweise Ihre vorgeschlagene Syntax (# 2) einige delimhäufiger erfordern würde , was wiederum eine häufigere Änderung von R""..""von erfordern würde R"delim"..."delim". Hoffe du kommst auf die Idee.

Könnte die Syntax besser sein? Ich persönlich würde eine noch einfachere Variante der Syntax bevorzugen:

Rdelim"string contents"delim;

Mit den obigen Beispielen:

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

Um jedoch korrekt zu funktionieren (wenn dies in der aktuellen Grammatik überhaupt möglich ist), würde diese Variante eine Beschränkung des Zeichensatzes für das delimTeil erfordern, beispielsweise nur auf Buchstaben / Ziffern (aufgrund vorhandener Operatoren), und möglicherweise einige weitere Einschränkungen für das ursprüngliche Zeichen auf Vermeiden Sie Konflikte mit einer möglichen zukünftigen Grammatik.
Ich glaube also, dass eine bessere Wahl hätte getroffen werden können, obwohl in diesem Fall nichts wesentlich Besseres getan werden kann.

Mikhail V.
quelle
Danke für die ausgearbeitete Antwort! Dies ist tatsächlich viel näher an dem, was ich gerne sehen würde. "OTOH, nachgestellte / führende / isolierte Zitate sind ziemlich oft" - nun, ich habe kein solches Gefühl. Aber das ist nur mein Gefühl. Wenn Sie eine große Anzahl öffentlicher Codebasen analysieren, werden Sie möglicherweise feststellen, dass dies tatsächlich der Fall ist. Aber für mich fühlt es sich wieder anders an.
Mikhail
Gutes Beispiel mit einer "Anführungszeichenfolge". Aber hey, versuchen Sie zu sagen, dass rohe String-Literale in allen Fällen so gut wie möglich aussehen sollten ? Ich möchte sie nur für Fälle optimieren, in denen nicht rohe String-Literale nicht gut genug sind. Und für beide Beispiele würde ich eigentlich ein nicht rohes String-Literal bevorzugen. Deshalb ist es mir egal, wie es für ein rohes String-Literal aussehen würde. Aber ich verstehe deinen Standpunkt. Vielen Dank.
Mikhail
@Mikhail "für Fälle, in denen nicht rohe String-Literale nicht gut genug sind". Alle Literale, bei denen ich möglicherweise ein Escapezeichen benötige, eignen sich nicht für viele Aufgaben (z. B. Platzieren von Zeichenfolgen mit DSL-Inhalten, z. B. JSON, Regex usw.). Ich sage also nur, dass diese Art von Literalen IMO echte Rohzeichenfolgen sein müssen und nicht Etwas halbgebackenes, daher entspricht die vorhandene Syntax meiner Erwartung einer korrekten technischen Lösung.
Mikhail V
Ja, man muss auf das Trennzeichen achten, aber das ist zumindest sichtbarer als Escape-Sequenzen. Wenn eine Zeichenfolge in der Analysephase an einer falschen Stelle endet - wahrscheinlich sehen Sie einen Fehler, aber bei falsch maskierten Sequenzen gibt es mehr Fälle für schwer zu erkennende Fehler und es ist mehr Tippfehler.
Mikhail V
101

Mit den Klammern können Sie ein benutzerdefiniertes Trennzeichen angeben:

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

In Ihrem Beispiel und in der typischen Verwendung ist das Trennzeichen einfach leer, sodass die Rohzeichenfolge von den Sequenzen R"(und eingeschlossen wird )".

Das Zulassen beliebiger Trennzeichen ist eine Entwurfsentscheidung, die den Wunsch widerspiegelt, eine vollständige Lösung ohne seltsame Einschränkungen oder Randfälle bereitzustellen. Sie können eine beliebige Zeichenfolge auswählen , die in Ihrer Zeichenfolge nicht als Trennzeichen vorkommt.

Ohne dies wären Sie in Schwierigkeiten, wenn die Zeichenfolge selbst etwas enthält "(wenn Sie nur R"..."als Roh-String-Syntax wollten ) oder )"(wenn das Trennzeichen leer ist). Beides sind sehr häufige und häufige Zeichenfolgen, insbesondere in regulären Ausdrücken. Daher wäre es unglaublich ärgerlich, wenn die Entscheidung, ob Sie eine Rohzeichenfolge verwenden oder nicht, vom spezifischen Inhalt Ihrer Zeichenfolge abhängt.

Denken Sie daran, dass es in der rohen Zeichenfolge keinen anderen Escape-Mechanismus gibt. Das Beste, was Sie sonst tun könnten, wäre, Teile des Zeichenfolgenliteral zu verketten, was sehr unpraktisch wäre. Wenn Sie ein benutzerdefiniertes Trennzeichen zulassen, müssen Sie lediglich einmal eine ungewöhnliche Zeichenfolge auswählen und diese möglicherweise in sehr seltenen Fällen ändern, wenn Sie eine zukünftige Bearbeitung vornehmen.

Um es noch einmal zu betonen, ist sogar das leere Trennzeichen bereits nützlich, da Sie mit der R"(...)"Syntax nackte Anführungszeichen in Ihre Zeichenfolge einfügen können. Das allein ist ein ziemlicher Gewinn.

Kerrek SB
quelle
9
Und nackte Zeilenumbrüche und Tabulatoren und Leerzeichen!
20етър Петров
3
Sicher, nur hervorheben, dass die () nicht da sind, um Backslashes und Leerzeichen zuzulassen. Das Trennzeichen wird nur benötigt, wenn Sie eine Zeichenfolge mit) "darin haben. ZB R" ("(zB)") "müsste ein Trennzeichen verwenden, R" Trennzeichen ("(zB)")) Trennzeichen " Ich bin damit einverstanden, dass die Syntax etwas unhandlich ist. In diesem Beispiel ist "" (zB) "für mich besser lesbar.
Superfly Jon
1
@AndyG: Ich meinte es in dem Sinne, dass )fooes nicht in Ihrer Zeichenfolge erscheint, einschließlich der Klammer. Die d-char-Sequenz selbst kann tatsächlich willkürlich erscheinen.
Kerrek SB
3
@Mikhail: Sie müssen nicht für jeden String rohe String-Literale verwenden. Es ist ein Urteilsspruch; Verwenden Sie es, wenn es die Sache verbessert. Der typische Anwendungsfall besteht entweder aus einer langen oder einer komplexen Zeichenfolge, sodass Sie sich auf den Körper konzentrieren und die Begrenzer beim Lesen grundsätzlich ignorieren.
Kerrek SB
7
@KerrekSB genauer, )fookann auch innerhalb der Zeichenfolge erscheinen, )foo"kann aber nicht. R"foo(Hello World )foo)foo"ist äquivalent zu "Hello World )foo".
Isarandi