std::num_get<CharT,InputIt>::get, std::num_get<CharT,InputIt>::do_get
public:
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, bool& v ) const;
| (1) | |
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, long& v ) const;
| (2) | |
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, long long& v ) const;
| (3) | (начиная с C++11) |
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, unsigned short& v ) const;
| (4) | |
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, unsigned int& v ) const;
| (5) | |
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, unsigned long& v ) const;
| (6) | |
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, unsigned long long& v ) const;
| (7) | (начиная с C++11) |
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, float& v ) const;
| (8) | |
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, double& v ) const;
| (9) | |
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, long double& v ) const;
| (10) | |
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, void*& v ) const;
| (11) | |
protected:
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, bool& v ) const;
| (12) | |
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, long& v ) const;
| (13) | |
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, long long& v ) const;
| (14) | (начиная с C++11) |
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, unsigned short& v ) const;
| (15) | |
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, unsigned int& v ) const;
| (16) | |
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, unsigned long& v ) const;
| (17) | |
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err,
unsigned long long& v ) const;
| (18) | (начиная с C++11) |
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, float& v ) const;
| (19) | |
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, double& v ) const;
| (20) | |
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, long double& v ) const;
| (21) | |
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, void*& v ) const;
| (22) |
do_get наиболее производного класса.in и формирует значение типа v с учетом флагов форматирования потока ввода-вывода из str.flags(), правил классификации символов из std::use_facet<std::ctype<CharT>>(str.getloc()) и символов числовой пунктуации из std::use_facet<std::numpunct<CharT>>(str.getloc()). Эта функция вызывается всеми операторами форматированного ввода из потока, например std::cin >> n;.Преобразование выполняется в три этапа:
Этап 1: выбор спецификатора преобразования
- Флаги формата ввода-вывода извлекаются, как если бы выполнялись
fmtflags basefield = (str.flags() & std::ios_base::basefield);fmtflags boolalpha = (str.flags() & std::ios_base::boolalpha);
- Если тип
vявляется целочисленным типом, выбирается первый подходящий вариант из следующих пяти:
- Если
basefield == oct, используется спецификатор преобразования%o - Если
basefield == hex, используется спецификатор преобразования%X - Если
basefield == 0, используется спецификатор преобразования%i - Если тип
vявляется знаковым, используется спецификатор преобразования%d - Если тип
vявляется беззнаковым, используется спецификатор преобразования%u
- Для целочисленных типов к спецификации преобразования при необходимости добавляется модификатор длины:
hдля short и unsignedshort,lдля long и unsignedlong,llдля longlong и unsignedlonglong(начиная с C++11) - Если тип
v— float, используется спецификатор преобразования%g - Если тип
v— double, используется спецификатор преобразования%lg - Если тип
v— longdouble, используется спецификатор преобразования%Lg - Если тип
v— void*, используется спецификатор преобразования%p - Если тип
v— bool иboolalpha == 0, выполнение продолжается так, как если бы типvбыл long, за исключением значения, которое должно быть сохранено вvна этапе 3. - Если тип
v— bool иboolalpha != 0, этапы 2 и 3 заменяются следующими действиями:- Последовательные символы, полученные из входного итератора
in, сравниваются с последовательностями символов, полученными изstd::use_facet<std::numpunct<CharT>>(str.getloc()).falsename()иstd::use_facet<std::numpunct<CharT>>(str.getloc()).truename(), только в той мере, в какой это необходимо для определения единственного совпадения. Входной итераторinсравнивается сendтолько тогда, когда необходимо получить символ. - Если целевая последовательность однозначно распознана,
vприсваивается соответствующее значение bool. В противном случаеfalseсохраняется вv, аstd::ios_base::failbitприсваиваетсяerr. Если до конца ввода (in == end) однозначное совпадение найти не удалось, выполняетсяerr |= std::ios_base::eofbit.
- Последовательные символы, полученные из входного итератора
Этап 2: извлечение символов
- Если
in == end, этап 2 немедленно завершается, дальнейшие символы не извлекаются. - Следующий символ извлекается из
in, как если бы выполнялосьchar_type ct = *in;:- Если символ совпадает с одним из
"0123456789abcdefxABCDEFX+-"(до C++11)"0123456789abcdefpxABCDEFPX+-"(начиная с C++11), преобразованных в char_type локали, как если бы выполнялосьstd::use_facet<std::ctype<CharT>>(str.getloc()).widen(), он преобразуется в соответствующий char. - Если символ совпадает с десятичным разделителем (
std::use_facet<std::numpunct<CharT>>(str.getloc()).decimal_point())), он заменяется на'.'. - Если символ совпадает с разделителем тысяч (
std::use_facet<std::numpunct<CharT>>(str.getloc()).thousands_sep()) и разделение на группы тысяч используется (что определяется с помощьюstd::use_facet<std::numpunct<CharT>>(str.getloc()).grouping().length() != 0), то, если десятичная точка'.'еще не накоплена, позиция символа запоминается, но сам символ игнорируется. Если десятичная точка уже накоплена, символ отбрасывается, и этап 2 завершается. - В любом случае проверяется, допустим ли char, полученный на предыдущих шагах, во входном поле, которое разбиралось бы с помощью
std::scanfи спецификатора преобразования, выбранного на этапе 1. Если символ допустим, он накапливается во временном буфере, и этап 2 повторяется. Если символ недопустим, этап 2 завершается.
- Если символ совпадает с одним из
Этап 3: преобразование и сохранение
- Последовательность символов char, накопленная на этапе 2, преобразуется в числовое значение:
Ввод разбирается согласно правилам std::scanf. | (до C++11) |
| (начиная с C++11) |
- Если функция преобразования не может преобразовать всё поле, значение
0сохраняется вv. - Если тип
vявляется знаковым целочисленным типом и функция преобразования возвращает положительное или отрицательное значение, слишком большое для его представления, вvсохраняется соответственно наибольшее положительное или отрицательное представимое значение. - Если тип
vявляется беззнаковым целочисленным типом и функция преобразования возвращает значение, которое невозможно в нём представить, вvсохраняется наибольшее представимое значение. - В любом случае, если функция преобразования завершается неудачей,
std::ios_base::failbitприсваиваетсяerr. - В противном случае числовой результат преобразования сохраняется в
v.- Если тип
v— bool и флаг boolalpha не установлен, то, если сохраняемое значение равно0, сохраняетсяfalse; если сохраняемое значение равно1, сохраняетсяtrue; для любого другого значенияstd::ios_base::failbitприсваиваетсяerrи сохраняетсяtrue.
- Если тип
- После этого проверяется группировка цифр. Если позиция любого разделителя тысяч, отброшенного на этапе 2, не соответствует группировке, заданной
std::use_facet<std::numpunct<CharT>>(str.getloc()).grouping(),std::ios_base::failbitприсваиваетсяerr. - Если этап 2 завершился в результате проверки
in == end, выполняетсяerr |= std::ios_base::eofbit, чтобы установить бит eof.
Возвращаемое значение
in
Примечания
До принятия решений по вопросу LWG 23 и вопросу LWG 696 значение v оставалось неизменным при возникновении ошибки.
До принятия решения по вопросу LWG 221 строки, представляющие шестнадцатеричные целые числа (например, "0xA0"), отклонялись функцией do_get(int), даже если являлись допустимым вводом для strtol, поскольку на этапе 2 символы 'X' и 'x' отфильтровываются.
До принятия решения по вопросу LWG 1169 преобразование строки с отрицательным числом в беззнаковое целое число могло давать ноль (поскольку значение, представленное строкой, меньше того, которое может представить целевой тип).
| До принятия решения по вопросу LWG 2381 строки, представляющие шестнадцатеричные числа с плавающей точкой с экспонентами (например, Строки, представляющие бесконечность или значение «не число» (например, | (начиная с C++11) |
Пример
Реализация operator>> для пользовательского типа.
#include <iostream>
#include <iterator>
#include <locale>
struct base { long x; };
template<class CharT, class Traits>
std::basic_istream<CharT, Traits>&
operator >>(std::basic_istream<CharT, Traits>& is, base& b)
{
std::ios_base::iostate err = std::ios_base::goodbit;
try // setting err could throw
{
typename std::basic_istream<CharT, Traits>::sentry s(is);
if (s) // if stream is ready for input
std::use_facet<std::num_get<CharT>>(is.getloc()).get(is, {}, is, err, b.x);
}
catch (std::ios_base::failure& error)
{
// handle the exception
}
return is;
}
int main()
{
base b;
std::cin >> b;
} Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были ретроактивно применены к ранее опубликованным стандартам C++.
| DR | Применяется к | Опубликованное поведение | Исправленное поведение |
|---|---|---|---|
| LWG 17 | C++98 | процесс разбора текстовых логических значений был ошибочным | исправлено |
| LWG 18 | C++98 | отсутствовала перегрузка get, принимающая значение bool& | добавлена |
| LWG 23 | C++98 | переполнение при вводе приводило к неопределённому поведению | обработка переполнения |
| LWG 154 | C++98 | спецификатор преобразования для double был %g (таким же, как для float) | изменён на %lg |
| LWG 221 | C++98 |
do_get не разбирал 'x' и 'X', тогда как strtol разбирал их | обеспечен разбор 'x' и 'X' |
| LWG 275 | C++98 |
get имел перегрузку, принимающую значение short& вместо float& | исправлено |
| LWG 358 | C++98 | разделители тысяч после десятичной точки игнорировались | при обнаружении завершается этап 2 |
| LWG 696 | C++98 | при ошибке преобразования результат оставался неизменным | установлен в ноль |
| LWG 1169 | C++98 | обработка переполнения была непоследовательной для типов с плавающей точкой | приведена в соответствие с strtof/strtod |
| LWG 2381 | C++11 |
do_get не разбирал 'p' и 'P', тогда как strtod разбирал их | обеспечен разбор 'p' и 'P' |
См. также
| извлекает форматированные данные (открытая функция-член std::basic_istream<CharT,Traits>) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/locale/num_get/get