чем std :: u8string будет отличаться от std :: string? - PullRequest
8 голосов
/ 03 июня 2019

Если у меня есть строка:

std::string s = u8"你好";

и в C ++ 20,

std::u8string s = u8"你好";

как std::u8string будет отличаться от std::string?

1 Ответ

7 голосов
/ 05 июня 2019

Поскольку разница между u8string и string заключается в том, что один шаблонизирован на char8_t, а другой на char, вопрос real заключается в том, в чем разница между использованием char8_t на основе строк против char на основе строк.

Это действительно сводится к следующему: кодирование на основе типов.

Любая строка на основе char (char*, char[], string и т. Д.) Может быть закодирована в UTF-8. Но опять же, это может не . Вы можете разработать свой код, исходя из предположения, что каждый эквивалент char* будет закодирован в UTF-8. И вы можете написать u8 перед каждым строковым литералом и / или иным образом убедиться, что они правильно закодированы. Но:

  1. Код других людей может не совпадать. Таким образом, вы не можете использовать любую библиотеку, которая может вернуть char* s, которые не используют кодировку UTF-8.

  2. Вы можете случайно нарушить свои собственные заповеди. Ведь char not_utf8[] = "你好"; условно поддерживается C ++. Кодировка этого char[] будет узкой кодировкой компилятора ... какой бы она не была . Это может быть UTF-8 на некоторых компиляторах и что-то еще на других.

  3. Вы не можете сказать кодам других людей (или даже другим людям в вашей команде), что это то, что вы делаете. То есть ваш API не может объявить, что определенный char* имеет кодировку UTF-8. Это должно быть что-то, что пользователь предполагает или прочел в вашей документации, а не то, что он видит в коде.

Обратите внимание, что ни одна из этих проблем не существует для пользователей UTF-16 или UTF-32. Если вы используете строку на основе char16_t, все эти проблемы исчезнут. Если код других людей возвращает строку char16_t, вы знаете, что они делают. Если они возвращают что-то еще, то вы знаете, что эти вещи, вероятно, не UTF-16. Ваш код на основе UTF-16 может взаимодействовать с их кодом. Если вы напишете API, который возвращает строку на основе char16_t, то каждый, кто использует ваш код, может видеть по типу строки, что это за кодировка. И это гарантированно будет ошибкой компиляции: `char16_t not_utf16 [] =" 你好 ";

Теперь да, нет гарантии ни на одну из этих вещей. Любая конкретная строка char16_t может иметь любые значения, даже те, которые недопустимы для UTF-16. Но char16_t представляет тип, для которого допущением по умолчанию является конкретная кодировка. Учитывая, что если вы представите строку с этим типом, которая не закодирована в кодировке UTF-16, было бы разумным считать это ошибкой / вероломством со стороны пользователя, что это нарушение контракта.

Мы можем видеть, как на C ++ повлияло отсутствие аналогичных средств на основе типов для UTF-8. Рассмотрим filesystem::path. Он может принимать строки в любой кодировке Unicode. Для UTF-16/32 конструктор path принимает строки на основе char16/32_t. Но вы не можете передать строку UTF-8 в конструктор path; конструктор на основе char предполагает, что кодирование является узким кодированием, определяемым реализацией, а не UTF-8. Поэтому вместо этого вы должны использовать filesystem::u8path, которая является отдельной функцией, которая возвращает a path, построенной из строки в кодировке UTF-8.

Что еще хуже, если вы попытаетесь передать строку в кодировке UTF-8, основанную на char, в конструктор path ... он прекрасно скомпилируется. Несмотря на то, что в лучшем случае он не переносимый, он может просто работать.

char8_t и все его атрибуты, такие как u8string, существуют, чтобы предоставить пользователям UTF-8 ту же мощность, что и другие кодировки UTF. В C ++ 20 filesystem::path получит перегрузки для строк на основе char8_t, а u8path устареет.

И, как дополнительный бонус, char8_t не имеет специального языка псевдонимов. Таким образом, API, который принимает строки char8_t, определенно API, который принимает массив символов, а не произвольный байтовый массив.

...