Символы, извлеченные istream> double
пример кода на Coliru:
#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). In [istream.форматированный.арифметика] у нас (перефразировано):
operator>>(double& val);
как и в случае вставщиков, эти экстракторы зависят от объекта num_get (22.4.2.1) локали для выполнения синтаксического анализа данных входного потока. Эти экстракторы ведут себя как форматированные входные функции (как описано в 27.7.2.2.1). После построения объекта sentry преобразование выполняется следующим фрагментом кода:
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 и определение соответствующего значения char для формата ожидается спецификацией преобразования, определенной на этапе 1.
- Этап 3: хранить результаты
в описании этапа 2, это слишком долго для меня, чтобы вставить все это здесь. Однако он ясно говорит, что все символы должны быть извлечены до попытки преобразования; и далее, что точно следующие символы должны быть извлечены:
- любой
0123456789abcdefxABCDEFX+-
- стандарта
decimal_point()
- стандарта
thousands_sep()
наконец, правила для Этапа 3 включают в себя:
- для значения с плавающей запятой функция
strtold
.числовое значение для хранения может быть одним из:
- ноль, если функция преобразования не может преобразовать все поле.
все это, кажется, четко указывает, что вывод моего кода должен быть 0, 'ipxngh'
. Тем не менее, это на самом деле выводит что-то другое.
это ошибка компилятора / библиотеки? Есть ли какое-либо положение, которое я пропускаю для локали, чтобы изменить поведение этапа 2? (In еще вопрос кто-то опубликовал пример системы, которая действительно извлекает символы, но также извлекает ipxn
которых нет в списке, указанном в N3337).
обновление
как отметил perreal, этот текст из Этапа 2 актуален:
если сбросить верно, то если'.'еще не было накоплено, то положение персонажа запоминается, но символ в противном случае игнорируется. В противном случае, если ’. уже накопленный, персонаж отбрасывается, и Этап 2 завершается. Если не отброшены, то проверка, чтобы определить, если
c
допускается в качестве следующего символа входного поля спецификатора преобразования, возвращаемого этапом 1. Если это так,то оно накапливается.если символ либо отбрасывается, либо накапливается, затем расширяется ++in и обработка возвращается к началу этапа 2.
Итак, Этап 2 может завершиться, если символ находится в списке разрешенных символов, но не является допустимым символом для %g
. Он не говорит точно, но, по-видимому, это относится к определению fscanf
от C99, который позволяет:
- непустая последовательность десятичных цифр, дополнительно содержащий десятичная точка символ, затем необязательная экспоненциальная часть, как определено в 6.4.4.2;
- a 0x или 0X, затем непустая последовательность шестнадцатеричных цифр, необязательно содержащая десятичный символ, затем необязательная двоичная экспонента, как определено в 6.4.4.2;
- INF или бесконечность, игнорируя case
- NAN или NAN (N-char-последовательность opt), игнорируя случай в части NAN, где:
и
In кроме локали "C", могут быть приняты дополнительные формы последовательности субъекта, специфичные для локали.
Итак, на самом деле вывод Coliru правильный; и на самом деле обработка должны попытка проверить последовательность символов, извлеченных до допустимого ввода %g
, при извлечении каждого персонажа.
следующий вопрос: Разрешено ли, как в потоке, с которым я связался ранее, принимать i
, n
, p
etc на этапе 2?
это допустимые символы для %g
, однако они не находятся в списке атомов, который Этап 2 разрешается читать (т. е. c == 0
для моей последней цитаты, поэтому персонаж не отбрасывается и не накапливается).
2 ответов
это беспорядок, потому что, вероятно, ни реализация gcc/libstdc++, ни Clang/libc++не соответствуют. Неясно," проверка производится для определения того, разрешен ли c в качестве следующего символа входного поля спецификатора преобразования, возвращаемого этапом 1", но я думаю, что использование фразы "следующий символ" указывает на то, что проверка должна быть контекстно-чувствительной (т. е. зависеть от символов, которые уже были накоплены), и поэтому попытка анализа, например, "21abc"
, следует прекратить, когда 'a'
встречаются. Это согласуется с обсуждением в LWG выпуск 2041, который добавил Это предложение обратно в стандарт после того, как оно было исключено во время разработки C++11. неспособность libc++сделать это ошибка 17782.
libstdc++, с другой стороны, отказывается анализировать "0xABp-4"
мимо 0
, который на самом деле явно не соответствует стандарту (он должен анализировать "0xAB"
как hexfloat, как ясно разрешено C99 fscanf
спецификация %g
).
прием i
, p
и n
не допускается стандартом. См.LWG выпуск 2381.
стандарт описывает обработку очень точно - это должно быть сделано "как будто" указанным фрагментом кода, который не принимает эти символы. Сравните разрешение LWG выпуск 221, в котором они добавили x
и X
в список персонажей потому что num_get
как тогда-описано не будет иначе разбирать 0x
для целочисленных входов.
Clang / libc++ принимает "inf" и "nan" вместе с hexfloats, но не "бесконечность" в качестве расширения. См.ошибка 19611.
в конце этапа 2, он говорит:
если он не отброшен, то выполняется проверка, чтобы определить, является ли c допускается в качестве следующего символа входного поля преобразования описатель возвращается на Этап 1. Если это так,то оно накапливается.
Если символ отбрасывается или накапливается, то in расширяется ++in и обработка возвращается к началу этапа 2.
Так что, возможно,a
Не допускается %g
спецификатор и он не накапливается или игнорируется.