С++ Когда символы расширены в операторе потока вывода <<()?

Мне кажется, что в стандарте С++ существует несогласованность, в частности в §30.7.5.2.4 проекта С++ 17 (N4659), о том, когда символы расширяются в форматированных выводах на выходных потоках ( operator<<()). Точно такая же несогласованность, по-видимому, отражена в en.cppreference.com.

Сначала предположим следующие объявления:

std::ostream out;
std::wostream wout;
char ch;
wchar_t wch;
const char* str;
const wchar_t* wstr;

Затем утверждается, что

  • out << ch не выполняет расширение символов,
  • out << str выполняет расширение символа,
  • wout << ch выполняет расширение символов,
  • wout << str выполняет расширение символов,
  • wout << wch не выполняет расширение символов,
  • wout << wstr выполняет расширение символов.

Первая и самая очевидная несогласованность заключается в том, что (6) не может быть истинным, так как нет функции widen(), принимающей аргумент wchar_t, только один, который принимает аргумент char.

Вторая (кажущаяся) несогласованность находится между (1) и (2). Мне кажется странным, что out << "x" должен расширять 'x', а out << 'x' не должен.

Я неправильно интерпретирую стандартный текст, или там что-то не так? Если последнее верно, знаете ли вы, что такое предполагаемое поведение?

EDIT: По-видимому, эта несогласованность (если я прав) присутствует в стандарте, поскольку, по крайней мере, С++ 03 (§27.6.2.5.4). Текст немного меняется через промежуточные стандарты, но несогласованность, как я объясняю выше, остается.

Ответ 1

Похоже, что стандарт не совсем правильный. Основная часть проблемы связана с объемной спецификацией соответствующих операций. Вместо обработки каждой перегрузки индивидуально похожие перегрузки описаны вместе, что приводит к вводящей в заблуждение спецификации.

Я сомневаюсь, что у любого разработчика есть проблемы с пониманием того, что предназначено. По существу, когда a char вставляется в поток не char, символ должен быть widen() ed, чтобы получить символ типа символа потока. Это расширение предназначено для сопоставления одного символа с исходным символом, установленным на один символ в широком наборе символов потока.

Обратите внимание, что спецификация IOStreams предполагает исходное понятие символов в потоках, являющихся отдельными объектами. Поскольку спецификация была создана (для версии С++ 1998), текст существенно не обновлялся, но при широком использовании Unicode "символы" в потоке действительно байты кодировки. Хотя потоки в основном работают нормально в этой модифицированной среде, некоторая гибкость, которая была бы полезной для работы с символами Unicode, на самом деле не поддерживается должным образом. Отсутствие чего-то "расширения" одного символа в последовательность байтов UTF8, вероятно, является одним из них.

Если вы считаете, что несоответствие/некорректность в разделе потока требует адресации, напишите отчет о дефекте. Инструкция по подаче отчетов о дефектах находится на http://isocpp.org. Когда вы поднимаете вопрос, подумайте о предоставлении предложенной формулировки для исправления проблемы. Поскольку нет недостатка в ясности, что на самом деле предназначено, и, вероятно, большинство реализаций делают все правильно, я бы ожидал, что эта проблема будет иметь довольно низкий приоритет, и без предложенной формулировки вряд ли это привлечет много внимания. Конечно, устранение проблемы не изменит предполагаемое поведение, например, "расширить" char в последовательность UTF8: это будет эффективно редизайн библиотеки потоков, которая может быть в порядке, но не будет выполнена как часть разрешения дефекта.