Яке обґрунтування дужок у необроблених рядкових літералах C ++ 11 R “(…)”?


75

У 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 Відповідь Керрека чудова, але, на жаль, це не відповідь. Оскільки я вже описав, що розумію, як це працює і які переваги це дає. З того часу, як я задав це питання, минуло п’ять років, і відповіді досі немає. І я все ще розчарований цим рішенням. Можна сказати, що це питання смаку, але я б не погодився. Скільки просторів ви використовуєте, як ви називаєте свої змінні, це SomeFunction()чи some_function()- це справа смаку. І я справді легко переходжу з одного стилю на інший.

Але це? .. Досі відчуваєш себе незграбним і незграбним через стільки років. Ні, це не стосується смаку. Це приблизно те, як ми хочемо висвітлити всі можливі випадки, незважаючи ні на що. Ми приречені писати ці потворні паренси щоразу, коли нам потрібно писати специфічний для Windows шлях, або регулярний вираз, або багаторядковий рядок-літерал. І для чого? .. Для тих рідкісних випадків, коли насправді нам потрібно ввести "рядок? Я хотів би бути на тому засіданні комітету, де вони вирішили зробити це таким чином. І я був би рішуче проти цього дійсно поганого рішення. Я бажаю. Зараз ми приречені.

Дякую, що прочитали це далеко. Зараз я почуваюся трохи краще.

UPD2 Ось мої альтернативні пропозиції, які, на мою думку, були б НАБАГАТО кращими за існуючі.

Пропозиція 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"#".

У вас є проблеми з цими пропозиціями?


13
R";-](R"(this is a basic raw string literal as text inside a more complex one)");-]"
pepper_chico

Синтаксис справді досить потворний imo, але я насправді не можу придумати альтернативу, яка також може залишатися зворотно сумісною і зберігати всі функції.
ChilliDoughnuts

@ChilliDoughnuts, дивіться оновлене запитання.
Михайло

1
@Mikhail: " Для тих рідкісних випадків, коли насправді нам потрібно поставити" у рядок? "Той факт, що ви вважаєте, що випадки, коли вам потрібен "необроблений рядок, є" рідкісними ", мабуть, є частиною проблеми. Справа не в тому, що немає" відповіді ". Є відповідь; ви просто не погоджуєтеся з нею . Якщо ваше визначення поняття "відповідь" - це "щось, що переконує мене передумати з цього приводу", тоді ваше запитання занадто самовпевнене. Обґрунтування надано; ваша згода з ним не потрібна.
Нікол Болас

1
Ви не повинні оновлювати історично високо оцінене запитання, щоб включити нове питання ... замість цього опублікувати нове запитання. (Що, мабуть, і так буде закрито як засноване на думках, оскільки єдиним вашим запереченням є "Я вважаю це неестетичним")
М. М.

Відповіді:


8

Як пояснює інша відповідь, до лапки повинно бути щось додаткове, щоб уникнути неоднозначності розбору у випадках, коли "або )", або фактично будь-яка закриваюча послідовність, яка може з’явитися в самому рядку.

Що стосується вибору синтаксису, то, погоджуюсь, вибір синтаксису неоптимальний , але це загалом нормально (ви можете подумати: "все може бути гірше", ха-ха). Я думаю, що це хороший компроміс між простотою використання та простотою синтаксичного аналізу.

Пропозиція 1 . Натхненний python. Неможливо підтримати рядкові літерали з потрійними лапками:
R "" "будь-який вміст, крім потрійних лапок, якими ви насправді не так часто користуєтеся."

У цьому справді є проблема - "лапки, якими ви насправді не так часто користуєтесь". По-перше, сама ідея необроблених рядків полягає в тому, щоб представляти необроблені рядки, тобто саме так, як вони могли б виглядати в текстовому файлі, без будь-яких змін у рядку, незалежно від вмісту рядка. По-друге, синтаксис повинен бути загальним, тобто без додавання варіантів типу "майже сирий рядок" тощо.

Як би ви написали одну цитату з цим синтаксисом? Дві цитати? Примітка - це дуже поширені випадки, особливо коли ваш код має справу з рядками та синтаксичним розбором.

Пропозиція 2 .
R "delim" вміст рядка "delim".
R "" Виглядає краще, чи не так? "".
R "#" Ось подвійні лапки: "", дякую "#".

Ну, цей може бути кращим кандидатом. Одна річ , хоча - звичайна справа (і я вважаю , що це було стимулюючим випадок для загальноприйнятому синтаксису), є те , що саме по собі подвійні лапки символ дуже поширений, і необроблені рядки повинні стати в нагоді для цих випадків.

Отже, давайте подивимось, звичайний синтаксис рядка:

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частини, скажімо лише на букви / цифри (через існуючі оператори), і, можливо, деякі додаткові обмеження для початкового символу на уникати зіткнень з можливою граматикою в майбутньому.
Тому я вважаю, що міг би бути зроблений кращий вибір, хоча в цьому випадку нічого суттєво кращого зробити не можна.


Дякую за розроблену відповідь! Це насправді набагато ближче до того, що я хотів би бачити. "OTOH, кінцеві / ведучі / окремі цитати трапляються досить часто" - ну, у мене такого відчуття немає. Але це лише моє відчуття. Можливо, якщо ви проаналізуєте величезний загальнодоступний набір кодових баз, то виявите, що це насправді так. Але знову ж таки, для мене це відчувається інакше.
Михайло

Хороший приклад із "рядком із лапками". Але привіт, ти намагаєшся сказати, що сирі літеральні рядки повинні виглядати якомога краще у всіх випадках? Я хотів би оптимізувати їх лише для випадків, коли не-необроблені рядкові літерали недостатньо хороші. І для обох прикладів я насправді вважаю за краще мати несирий літеральний рядок. Ось чому мені все одно, наскільки це буде виглядати для необробленого літерального рядка. Але я бачу вашу думку. Дякую.
Михайло

@Mikhail "для випадків, коли не сировинні рядкові літерали недостатньо хороші". Будь-які літерали, де мені може знадобитися якийсь екран, не підходять для багатьох завдань (наприклад, розміщення рядків із вмістом DSL, наприклад, JSON, Regex тощо). Тому я просто кажу, що цей тип літералів IMO повинен бути справжніми необробленими рядками, а не щось напіввисоте, таким чином, існуючий синтаксис відповідає моїм очікуванням правильного технічного рішення.
Михайло V

Так, треба стежити за роздільником, але це принаймні помітніше, ніж послідовності виходу. Якщо рядок закінчується в неправильному місці на етапі синтаксичного аналізу - швидше за все, ви бачите якусь помилку, але у випадку неправильно екранованих послідовностей, випадків важко помітних помилок є більше, і це більше роздратування при наборі тексту.
Михайло V

101

Мета дужок - дозволити вам вказати власний роздільник:

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

У вашому прикладі та при типовому використанні роздільник просто порожній, тому необроблений рядок укладається послідовностями R"( та )".

Дозвіл на довільні роздільники - це дизайнерське рішення, яке відображає прагнення запропонувати повне рішення без дивних обмежень та крайових випадків. Ви можете вибрати роздільник будь-яку послідовність символів, яка не зустрічається у вашому рядку.

Без цього у вас би виникли проблеми, якби рядок містив щось на зразок "(якби ви просто хотіли, щоб R"..."ваш сирий сирий рядок) або )"(якщо роздільник порожній). І те, і інше є цілком поширеними та частими послідовностями символів, особливо у регулярних виразах, тому було б надзвичайно прикро, якби рішення про використання необробленого рядка залежало від конкретного вмісту рядка.

Пам’ятайте, що всередині необробленого рядка немає іншого механізму втечі, тому найкраще, що ви могли б зробити інакше, було об’єднати фрагменти рядкового літералу, що було б дуже недоцільно. Дозволивши спеціальний роздільник, все, що вам потрібно зробити, це вибрати один раз незвичайну послідовність символів та можливо, змінити її у дуже рідкісних випадках, коли ви робите майбутні зміни.

Але ще раз наголосимо, навіть порожній роздільник вже корисний, оскільки R"(...)"синтаксис дозволяє розміщувати голі лапки у вашому рядку. Це саме по собі є цілком вигідним.


9
І оголені нові рядки, і вкладки, і пробіли!
Петър Петров

3
Звичайно, лише підкресливши, що () тут немає, щоб дозволити зворотні скісні риски та пробіли. Розділювач потрібен лише у тому випадку, якщо у вас є рядок із символом "". Наприклад, R "(" (наприклад) ")" потрібно буде використовувати роздільник, R "розділити (" (наприклад, "))). погоджуюся, що синтаксис трохи громіздкий, у цьому прикладі "\" (наприклад, \ "", мені читабельніший.
Superfly Jon

1
@AndyG: Я мав на увазі це в тому сенсі, )fooякий не відображається у вашому рядку, включаючи дужки. Сама послідовність d-char може справді виглядати довільно.
Kerrek SB

3
@Mikhail: Вам не потрібно використовувати необроблені літеральні рядки для кожного рядка. Це судовий виклик; використовуйте його, коли це покращує ситуацію. Типовий варіант використання матиме довгий або складний рядок, щоб ви концентрувались на тілі і в основному ігнорували роздільники під час читання.
Kerrek SB

7
Точніше @KerrekSB )fooтакож може з'являтися всередині рядка, але )foo"не може. R"foo(Hello World )foo)foo"еквівалентно "Hello World )foo".
isarandi
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.