Ситуация с char8_t / UTF8 chars pre-C ++ 17 и плохая работа? - PullRequest
1 голос
/ 26 января 2020

Я читал ссылки как этот вопрос и, конечно, этот вопрос о подготовке к следующему типу символов utf8 char8_t и соответствующему им строковому типу в C + +20, и могу сказать, до определенного момента, что пора. Кроме того, это беспорядок.

Не стесняйтесь исправить меня, где я не прав:

  • C ++, любые стандарты, не имеют средств, чтобы указать, что исходный код имеет заданный текст кодирование (что-то вроде Python # encoding:... метаданные), а также какие стандарты могут быть скомпилированы (например, #!/bin/env g++ -std=c++14).
  • Вплоть до C ++ 11 также не было никакого способа укажите, что любой заданный строковый литерал будет иметь заданную кодировку - компилятор может свободно преобразовать строковый литерал UTF8 в, скажем, UTF16 или даже EBCDI C, если он того пожелает.
  • C ++ 11 вводит u16"text" и u32"text" и связанные с ними типы символов для создания текста в кодировке UTF16 и UTF32, но не предоставляет возможности для работы со строками или потоками, поэтому они в основном бесполезны .
  • C ++ 11 также вводит u8"text" для создания строки в кодировке UTF8 ... но даже не вводит либо правильный тип UTF8 char, либо строковый тип (это то, что char8_t должен быть в C ++ 20?), поэтому он даже полезнее, чем выше.
  • Из-за всего этого, когда char8_t равен наконец введено, оно убивает много кода, который должен был быть действительным, и до сих пор некоторые из требуемых исправлений включают отключение поведения char8_t в целом .
  • Даже тогда есть нет легкодоступных инструментов (как в: не тот же интерфейс уровня дерьма, что и <random>) для проверки, преобразования (в пределах одной строки) или преобразования (копирования между строковыми типами) текстовых кодировок в C ++. Кажется, даже codecvt был отброшен.

Учитывая все вышеизложенное, у меня есть несколько вопросов относительно того, почему мы находимся в этом странном состоянии и будет ли когда-нибудь лучше. Исторически поддержка Unicode была одной из самых низких точек в C ++.

Точно так же мне интересно, насколько полезна эмуляция бедного человека всей концепции (отказ от ответственности: я поддерживаю cxxomfort Я уже бэкпорт много чего. Рабочие потребности: последний MSV C цель в офисе MSV C 2012).

  • Почему C ++ не добавил char8_t в нужное время, когда u8"text" был введен или иным образом задержал введение u8?
  • В качестве альтернативы, почему не был введен другой, неразрывный префикс, такой как c8"text", введенный с char8_t в C + +20 вместо внесения масштабных изменений? Я думал, что TPTB ненавидел прерывая изменения, даже больше того, что буквально нарушает простейший возможный случай: cout<< prefix"hello world".
  • Является ли char8_t функциональным образом, чтобы быть (ближе к) псевдонимом unsigned char или char?
  • Если первое, работает ли, например: typedef std::basic_string<unsigned char> u8string жизнеспособная стратегия эмуляции? Доступны ли реализации бэкпорта / ссылки, на которые можно посмотреть, прежде чем писать мою собственную?
  • Что нам ближе всего в C ++ 17 или ниже для обозначения текста как (предназначенного для) UTF-8 * для только для хранения *?

re: char8_t как unsigned char, это более или менее то, что я смотрю в терминах псевдокода:

// this is here basically only for type-distinctiveness
class char8_t {
  unsigned char value;

  public:
  non_explicit constexpr char8_t (unsigned char ch = 0x00) noexcept;
  operator unsigned char () const noexcept;
  // implement all operators to mirror operations on unsigned char
};

// public adapter jic
friend unsigned char to_char (char8_t);

// note we're *not* using our new char-type here
namespace std {
  typedef std::basic_string<unsigned char> u8string;
}

// unsure if these two would actually be needed
// (couldn't make a compelling case so far,
// even testing with Windows's broken conhost)

namespace std {
  basic_istream<char8_t> u8cin;
  basic_ostream<char8_t> u8cout;
}

// we work up operator<<, operator>> and string conversion from there
// adding utf8-validity checks where needed

std::ostream& operator<< (std::ostream&, std::u8string const&);
std::istream& operator>> (std::istream&, std::u8string&);

// likely a macro; we'll see
#define u8c(ch) static_cast<char8_t>(ch)
// char8_t ch = u8c('x');

// very likely not a macro pre-C++20; can't skip utf-8 validity check on [2]?
u8string u8s (char8_t const* str); // [1], likely trivial
u8string u8s (char const* str);    // [2], non-trivial
// C++20 and up
#define u8s(str) u8##str // or something; not sure

// end result:

// no, I can't even think how would one spell this:
u8string text = u8s("H€łlo Ẅørλd");
// this wouldn't work without refactoring u8string into a full specialization, 
// to add the required constructor, but doing so is a PITA because 
// the basic_string interface is YAIM (yet another infamous mess):
u8string text = u8"H€łlo Ẅørλd";

I ' Мы пометили этот C ++ как общее, но это больше о (значении) реализации стандартов до C ++ 20. Что еще более важно, я не ищу "1079 * совершенных " решений или обоснований; учитывая контекст, бедняк более чем достаточно.

1 Ответ

2 голосов
/ 30 января 2020

Я являюсь автором P0482 и P1423 char8_t.

Кроме того, это беспорядок.

Я полностью согласен. SG16 работает над улучшением всех вещей, связанных с Юникодом и текстом, но мы должны начать с уровня земли, так что это займет некоторое время.

Если вы еще не видели Тем не менее, репозиторий, связанный ниже, предоставляет некоторые утилиты для написания кода, который будет работать на C ++ 17 и C ++ 20.

C ++, любые стандарты, не имеют средств для указания того, что исходный код имеет заданную кодировку текста (что-то вроде Python 'encoding: ... метаданные), и какие стандарты он может быть скомпилирован в (как, скажем, #! / bin / env g ++ -std = c ++ 14).

Это правильно, но не без прецедента. Компилятор IBM xl C поддерживает директиву #pragma filetag, которая действует аналогично объявлению кодировки Python. Я начал на бумаге, исследуя это место, и надеялся представить его для пражской встречи, но не успел завершить его вовремя. Я ожидаю представить его на совещание в Варне (в июне).

Вплоть до C ++ 11 не было никакого способа указать, что у любого заданного строкового литерала будет заданная кодировка - компилятор был свободен для преобразования строкового литерала UTF8 в, скажем, UTF16 или даже EBCDI C, если он того пожелал.

Правильно, и это технически остается верным для строковых литералов char16_t и char32_t до C ++ 20 и принятия P1041 . Обратите внимание, что повторного анализа не происходит. На этапе перевода 1 содержимое исходного кода преобразуется во внутреннюю кодировку компилятора, а затем на этапе перевода 5 символьные и строковые литералы преобразуются в кодировку соответствующего набора символов выполнения. .

C ++ 11 вводит u16 «текст» и u32 «текст» и связанные типы символов для создания текста в кодировке UTF16 и UTF32, но не предоставляет строковых или потоковых средств для работы с ними, поэтому они в основном бесполезны.

Правильно. P1629 - одно из наиболее значительных изменений, которые мы надеемся завершить в C ++ 23. Цель состоит в том, чтобы предоставить кодировщики текста, декодеры и транскодеры, которые облегчают работу с текстом на уровне кодовой единицы и кодовой точки. Мы также обеспечили бы поддержку перечисления графемных кластеров.

C ++ 11 также вводит u8 «текст» для создания строки в кодировке UTF8 ... но даже не вводит ни правильный тип UTF8 char или строковый тип (это то, что char8_t предназначен для C ++ 20?), так что он даже полезнее, чем выше.

Правильно. Целью C ++ 20 было: 1) включить разграничение "text" и u8"text" в системе типов, 2) включить разделение зависимого от локали и текста UTF-8 (с применением системы типов), 3) обеспечить использование тип без знака для кодовых единиц UTF-8 и 4) избегать штрафа за наложение типа char. Это было все, что мы успели сделать для C ++ 20 (стандартизация не быстрый процесс).

Из-за всего этого, когда наконец-то вводится char8_t, он убивает много кода, который должен был быть допустимым, и до сих пор некоторые из искомых исправлений включают в себя полное отключение поведения char8_t.

Правильно, char8_t было предложено как критическое изменение; что-то не следует воспринимать легкомысленно. В этом случае это было сочтено приемлемым, потому что 1) при поиске кода было обнаружено незначительное использование u8 символьных и строковых литералов, 2) варианты решения проблем обратной совместимости, которые обсуждались в P1423, были сочтены адекватными, и 3) предложение о неразрывности добавил бы в язык долгосрочный багаж за небольшую выгоду.

Даже в этом случае нет легкодоступного инструментария (как в: не тот же интерфейс уровня дерьма, что и) для проверки, преобразования (в пределах того же самого строка) или конвертировать (копирование через строковые типы) текстовые кодировки в C ++. Кажется, даже codecvt пропал.

Правильно. Мы будем работать над улучшением этой ситуации, но это займет время. codecvt не было отброшено (пока); заголовок <codecvt> и различные UTF-преобразователи устарели в C ++ 17. std::codecvt страдает от проблем с производительностью и удобством использования, поэтому мы не можем продолжать развивать это. Мы считаем, что P1629 - превосходное направление.

Почему C ++ не добавил char8_t в надлежащее время, когда был введен u8 «текст», или иным образом задержал введение u8?

Я спросил одного из членов комитета C ++, который участвовал в этой первоначальной работе. Он сказал мне, что спросил у людей, работающих над Unicode, нужно ли добавить новый тип, и ответил: «Э, нам это не нужно».

В качестве альтернативы, почему Не является ли еще один неразрывный префикс, такой как текст «c8», введенный с char8_t в C ++ 20 вместо внесения широкомасштабных изменений? Я думал, что TPTB ненавидит ломать изменения, даже больше того, что буквально ломает простейший возможный случай: префикс cout << hello world. </p>

Был рассмотрен другой префикс, и в какой-то момент я кратко одобрил этот подход , Однако, как упоминалось ранее, это оставило бы у нас два способа написания литералов UTF-8 и связанного исторического багажа. В долгосрочной перспективе считалось, что критическое изменение, если у нас есть разумные средства для смягчения поломки, дает больше преимуществ.

Что касается этого простого контрольного примера, уделите минуту, чтобы подумать о том, что этот код должен сделать. Затем go прочитайте это: Что такое символ форматирования printf () для char8_t *? .

Является ли char8_t функционально (ближе к) псевдонимом неподписанного символа или чар?

char8_t преднамеренно и явно не является псевдонимом (поскольку это имеет негативные последствия для производительности), но задано для того же базового представления, что и unsigned char. Причина, по которой unsigned char превышает char, состоит в том, чтобы избегать выражений типа u8'\x80' < 0, когда-либо имеющих значение true (что может или не может иметь место в случае char сегодня).

Если первое работает ли, например: typedef std :: basic_string u8string жизнеспособной стратегии эмуляции? Доступны ли реализации бэкпорта / ссылки, на которые можно посмотреть, прежде чем писать мою собственную?

Я не буду комментировать, является ли этот подход хорошей идеей или нет, но это было сделано раньше. Например, EASTL имеет такой typedef (Этот проект также предоставляет определение char8_t, если собственный тип недоступен )

Что ближе всего мы имеем в C ++ 17 или ниже для маркировки текста как (предназначенного для) UTF-8 только для хранения ?

Я не думаю, что там один правильный ответ на этот вопрос. Я видел, как проекты используют unsigned char или предоставляют char8_t подобный тип через класс.

Что касается вашего псевдокода, некоторые изменения в коде в ранее упомянутом char8_t-remediation хранилище для предоставления unsigned char типов вместо char должно разрешить работу кода, подобного следующему. См. определения пользовательских литералов _as_char и U8 макроса .

typedef std::basic_string<unsigned char> u8string;
u8string u8s(U8("text"));
...