Символы, извлеченные из istream & gt; & gt; двойной

Образец кода в Колиру:

#include <iostream>
#include <sstream>
#include <string>

int main()
{
double d; std::string s;

std::istringstream iss("234cdefipxngh");
iss >> d;
iss.clear();
iss >> s;
std::cout << d << ", '" << s << "'\n";
}

Я зачитываю здесь N3337 (предположительно, это то же самое, что и C ++ 11). В [istream.formatted.arithmetic] мы имеем (перефразировано):

operator>>(double& val);

Как и в случае со вставками, эти экстракторы зависят от num_get локали<> (22.4.2.1) объект
выполнить синтаксический анализ данных входного потока. Эти экстракторы ведут себя как отформатированные функции ввода (как
описано в 27.7.2.2.1). После того, как часовой объект создан, преобразование происходит так, как если бы оно выполнялось следующим фрагментом кода:

typedef num_get< charT,istreambuf_iterator<charT,traits> > numget;

iostate err = iostate::goodbit;

use_facet< numget >(loc).get(*this, 0, *this, err, val);

setstate(err);

Глядя на 22.4.2.1:

Детали этой операции происходят в три этапа

— Этап 1: определить спецификатор конверсии

— Стадия 2: извлечение символов из in и определение соответствующего значения символа для формата
ожидается согласно спецификации преобразования, определенной на этапе 1.

— Этап 3: результаты магазина

В описании Стадии 2 я слишком долго вставляю все это сюда. Однако в нем четко сказано, что все символы должны быть извлечены до попытки преобразования; и далее, что именно следующие символы должны быть извлечены:

  • любой из 0123456789abcdefxABCDEFX+-
  • Локаль decimal_point()
  • Локаль thousands_sep()

Наконец, правила для Стадии 3 включают в себя:

— Для значения с плавающей запятой функция strtold,

Числовое значение, которое будет сохранено, может быть одним из:

— ноль, если функция преобразования не может преобразовать все поле.

Кажется, все это четко указывает на то, что вывод моего кода должен быть 0, 'ipxngh', Тем не менее, это на самом деле выводит что-то еще.

Это ошибка компилятора / библиотеки? Есть ли какое-то положение, которое я пропускаю, чтобы локаль изменила поведение этапа 2? (В Другой вопрос кто-то опубликовал пример системы, которая на самом деле извлекает символы, но также извлекает ipxn которых нет в списке, указанном в N3337).

Обновить

Как указывает Perreal, этот текст из Стадии 2 актуален:

Если сброс — это правда, то, если ’.’ Еще не накоплено, то положение персонажа
запоминается, но персонаж игнорируется. В противном случае, если «уже было
накапливается, персонаж отбрасывается, и этап 2 заканчивается. Если это не отбрасывается, то
выполняется проверка, чтобы определить, c допускается в качестве следующего символа поля ввода спецификатора преобразования, возвращаемого этапом 1. Если это так, он накапливается.

Если символ либо отбрасывается, либо накапливается, то в него добавляется ++ in и выполняется обработка
возвращается к началу этапа 2.

Таким образом, этап 2 может завершиться, если символ находится в списке разрешенных символов, но не является допустимым символом для %g, Это не говорит точно, но, вероятно, это относится к определению fscanf от C99, что позволяет:

  • непустая последовательность десятичных цифр, необязательно содержащая десятичную точку
    символ, затем необязательная часть экспоненты, как определено в 6.4.4.2;
  • 0x или 0X, то непустая последовательность шестнадцатеричных цифр, необязательно содержащая
    символ десятичной точки, затем необязательная двоичная экспоненциальная часть, как определено в 6.4.4.2;
  • INF или INFINITY, игнорируя регистр
  • NAN или NAN (опция n-char-sequence opt), игнорируя регистр в части NAN, где:

а также

В отличие от локали «C», могут быть приняты дополнительные формы предметной последовательности, специфичные для локали.

Итак, на самом деле вывод Coliru правильный; и на самом деле обработка должен попытаться проверить последовательность символов, извлеченных до допустимого ввода в %g, извлекая каждый символ.

Следующий вопрос: разрешено ли, как в ветке, на которую я ссылался ранее, принять i , n, p и т.д. на этапе 2?

Это допустимые символы для %g однако их нет в списке атомов, которые Стадии 2 разрешено читать (т.е. c == 0 за мою последнюю цитату, поэтому персонаж не сбрасывается и не накапливается).

6

Решение

Это беспорядок, потому что вполне вероятно, что ни реализация gcc / libstdc ++, ни реализация clang / libc ++ не соответствуют. Непонятно, «выполняется проверка, чтобы определить, разрешен ли c как следующий символ поля ввода спецификатора преобразования, возвращаемого на этапе 1», но я думаю, что использование фразы «следующий символ» означает, что проверка должна быть контекстно-зависимый (т.е. зависящий от уже накопленных символов), и, таким образом, попытка разобрать, например, "21abc", должен остановиться, когда 'a' встречается. Это согласуется с обсуждением в Выпуск LWG 2041, который добавил это предложение обратно в стандарт после того, как он был удален во время разработки C ++ 11. отказ libc ++ сделать это ошибка 17782.

libstdc ++, с другой стороны, отказывается анализировать "0xABp-4" мимо 0, который на самом деле явно не соответствует на основе стандарта (он должен анализировать "0xAB" в виде шестигранника, как четко разрешено C99 fscanf спецификация для %g).

Принятие i, p, а также n не допускается стандартом. Увидеть Выпуск LWG 2381.

Стандарт описывает обработку очень точно — она ​​должна выполняться «как если бы» указанным фрагментом кода, который не принимает эти символы. Сравните разрешение LWG выпуск 221, в котором они добавили x а также X в список символов, потому что num_get как тогда описано не будет анализировать 0x для целочисленных входов.

Clang / libc ++ принимает «inf» и «nan» вместе с hexfloats, но не «infinity» как расширение. Увидеть ошибка 19611.

5

Другие решения

В конце этапа 2 говорится:

Если он не отбрасывается, выполняется проверка, чтобы определить, является ли c
разрешено в качестве следующего символа входного поля преобразования
спецификатор, возвращаемый на этапе 1. Если это так, он накапливается.

Если символ либо отбрасывается, либо накапливается, то значение in повышается с помощью ++ in, и обработка возвращается к началу этапа 2.

Так что возможно a не допускается в %g спецификатор и он не накапливается или игнорируется.

4

По вопросам рекламы [email protected]