Персонажи, извлеченные istream >> double
Образец кодав Колиру:
#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 повышается с помощью ++ in, и обработка возвращается к началу этапа 2.
Таким образом, этап 2 может завершиться, если символ находится в списке разрешенных символов, но не является допустимым символом для%g
, Это не говорит точно, но, вероятно, это относится к определениюfscanf
от C99, что позволяет:
а также
В отличие от локали "C", могут быть приняты дополнительные формы предметной последовательности, специфичные для локали.
Итак, на самом деле вывод Coliru правильный; и на самом деле обработкадолжен попытаться проверить последовательность символов, извлеченных до допустимого ввода в%g
, извлекая каждый символ.
Следующий вопрос: разрешено ли, как в ветке, на которую я ссылался ранее, принятьi
, n
, p
и т.д. на этапе 2?
Это допустимые символы для%g
однако они не находятся в списке атомов, которые Стадии 2 разрешено читать (т.е.c == 0
для моей последней цитаты, поэтому персонаж не сбрасывается и не накапливается).