web-dev-qa-db-ja.com

C ++ 11の生の文字列リテラルR "(...)"の括弧の理論的根拠は何ですか?

C++ 11には、生の文字列リテラルと呼ばれる非常に便利な機能があります。これは、エスケープ文字のない文字列です。そして、これを書く代わりに:

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

これを簡単に書くことができます:

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

かなり読みやすい。ただし、生の文字列リテラルを定義するために配置しなければならない文字列の周りに余分な括弧があることに注意してください。

私の質問は、なぜこれらが必要なのですか?私にとっては非常にくて非論理的です。ここに私が見る短所があります:

  • 機能全体がリテラルをよりコンパクトにするために使用される一方で、余分な冗長性
  • リテラルの本体と定義シンボルの区別が難しい

それは私が難しい区別によって意味するものです:

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

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

そして、ここにプロがあります:

  • 特に区切り文字とともに使用した場合、より柔軟で、生の文字列でより多くの文字を使用できます:"delim( can use "()" here )delim"

しかし、もっと柔軟性が必要な場合は、古い良いエスケープ可能な文字列リテラルがあります。標準委員会が、これらの絶対に不要な括弧ですべての生の文字列リテラルの内容を汚染することにしたのはなぜですか?その背後にある理由は何ですか?私が言及しなかったプロは何ですか?

[〜#〜] upd [〜#〜] Kerrekの答えは素晴らしいですが、残念ながら答えではありません。すでに説明したので、それがどのように機能し、どのような利点があるのか​​を理解しています。この質問をしてから5年が経ちましたが、まだ答えはありません。そして、私はまだこの決定にイライラしています。これは好みの問題だと言えますが、私は同意しません。使用するスペースの数、変数の名前の付け方は、このSomeFunction()またはsome_function()です。これは好みの問題です。そして、あるスタイルから別のスタイルに簡単に切り替えることができます。

しかし、これ?..何年も経った今でも、ぎこちなく不器用だと感じています。いいえ、これは味に関するものではありません。これは、どのような場合でも、考えられるすべてのケースをカバーする方法です。 Windows固有のパス、正規表現、または複数行の文字列リテラルを記述する必要があるたびに、これらのい括弧を書く運命にありました。そして何のために?。実際に文字列に_"_を入れる必要があるようなまれなケースでは?私は彼らがこの方法でそれを行うことを決めた委員会会議にいたことを望みます。そして、私はこの本当に悪い決断に強く反対するでしょう。私は望む。今、私たちは運命にあります。

ここまで読んでくれてありがとう。今は少し気分が良くなりました。

PD2ここに私の代替案がありますが、どちらも既存のものよりもはるかに優れていると思います。

提案1. pythonに触発されました。三重引用符付きの文字列リテラルをサポートできません:_R"""Here is a string literal with any content, except for triple quotes, which you don't actually use that often."""_

提案2.常識に触発された。現在の文字列_R"delim"content of string"delim"_と同様に、可能なすべての文字列リテラルをサポートします。区切り文字が空の場合:_R""Looks better, doesn't it?""_。空の生の文字列:_R""""_。二重引用符付きの生の文字列:_R"#"Here are double quotes: "", thanks"#"_。

これらの提案に問題はありますか?

67
Mikhail

他の答えが説明するように、"または)"の場合、または実際に文字列自体に現れる可能性のある終了シーケンスの場合の解析のあいまいさを避けるために、引用符に追加する必要があります。

構文の選択については、まあ、構文の選択はsuboptimalであることに同意しますが、一般的には問題ありません(考えられるかもしれません:「事態は悪化する可能性があります」、笑) 。使い方の単純さと構文解析の単純さとの間の良い妥協点だと思います。

プロポーザル1。 pythonに触発されました。三重引用符付きの文字列リテラルをサポートできません:
R "" "トリプルクォートを除くすべてのコンテンツ。実際にはそれほど頻繁には使用しません。" ""

これには確かに問題があります-「クォート、実際にはそれほど頻繁に使用しない」。まず、生の文字列の概念は、raw文字列を表すことです。つまり、テキストファイルに表示されるとおりにany文字列の内容に関係なく、文字列を変更します。次に、構文は一般的である必要があります。つまり、「ほとんど生の文字列」などのバリエーションを追加しないでください。

この構文で引用符をどのように記述しますか? 2つの引用符?注-これらは非常に一般的なケースで、特にコードが文字列と解析を処理している場合です。

プロポーザル2
R "delim"文字列のコンテンツ "delim"。
R ""見た目が良いですね。 ""。
R "#"二重引用符: ""、ありがとう "#"。

まあ、これはより良い候補かもしれません。ただし、よくあるケース(および受け入れられた構文の動機付けのケースだと思います)は、二重引用符自体がvery共通であり、生の文字列が入力されることですこれらの場合に便利です。

それでは、通常の文字列構文を見てみましょう。

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

あなたの構文「x」をデリムとして:

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

受け入れられる構文:

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

はい、角かっこが迷惑な視覚効果をもたらすことに同意します。したがって、)"は文字列内にあまり出現しないため、この場合の追加の「デリム」はほとんど必要ないという考えの後に、構文の作成者がいたと思います。しかし、OTOH、後続/先頭/分離された引用は非常に頻繁にあります。提案された構文(#2)はいくつかのdelimをより頻繁に必要とし、それはR""..""からR"delim"..."delim"への変更をより頻繁に必要とします。あなたがアイデアを得ることを願っています。

構文は改善できますか?私は個人的には構文のさらに単純なバリアントを好むでしょう:

Rdelim"string contents"delim;

上記の例では:

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

ただし、(現在の文法で可能な限り)正しく動作するために、このバリアントではdelim部分の文字セットを、たとえば既存の演算子のために文字/数字のみに制限する必要があります。将来の文法との衝突を避けるための初期文字の制限。
したがって、この場合はより良い何も行うことはできませんが、より良い選択を行うことができたと思います。

5
Mikhail V

括弧の目的は、カスタム区切り文字を指定できるようにすることです。

_R"foo(Hello World)foo"   // the string "Hello World"
_

あなたの例では、そして通常の使用では、区切り文字は単に空なので、生の文字列はシーケンス_R"(_と_)"_で囲まれています。

任意の区切り文字を許可することは、奇妙な制限やEdgeケースのない完全なソリューションを提供したいという要望を反映した設計上の決定です。 任意の文字列を区切り文字として文字列に出現しない文字列を選択できます。

これがないと、文字列自体に_"_(生の文字列構文として_R"..."_が必要な場合)または_)"_(区切り文字が空の場合)のようなものが含まれている場合に問題が発生します。 。どちらも完全に一般的で頻繁な文字シーケンスであり、特に正規表現では、生の文字列を使用するかどうかの決定が文字列の特定のコンテンツに依存する場合、非常に面倒です。

生の文字列の内部には他のエスケープメカニズムがないため、文字列リテラルの断片を連結することが最善であり、これは非常に非現実的です。カスタム区切り文字を許可することにより、あなたがする必要があるのは、珍しい文字シーケンスを一度選択し、maybe将来を作るときに非常にまれなケースでそれを変更することです編集。

しかし、もう一度強調するために、R"(...)"構文を使用すると、文字列に裸の引用符を配置できるため、空の区切り文字でも既に役立ちます。それ自体はかなりの利益です。

95
Kerrek SB