std::num_get<CharT,InputIt>::get, std::num_get<CharT,InputIt>::do_get
| (1) | ||
public:
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, bool& v ) const;
| ||
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, long& v ) const;
| ||
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, long long& v ) const;
| (с C++11) | |
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, unsigned short& v ) const;
| ||
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, unsigned int& v ) const;
| ||
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, unsigned long& v ) const;
| ||
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, unsigned long long& v ) const;
| (с C++11) | |
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, float& v ) const;
| ||
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, double& v ) const;
| ||
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, long double& v ) const;
| ||
iter_type get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, void*& v ) const;
| ||
| (2) | ||
protected:
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, bool& v ) const;
| ||
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, long& v ) const;
| ||
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, long long& v ) const;
| (с 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;
| ||
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, unsigned int& v ) const;
| ||
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, unsigned long& v ) const;
| ||
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;
| (с 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;
| ||
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, double& v ) const;
| ||
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, long double& v ) const;
| ||
virtual iter_type do_get( iter_type in, iter_type end, std::ios_base& str,
std::ios_base::iostate& err, void*& v ) const;
|
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 и unsigned short,lдля long и unsigned long,llдляlong longиunsigned long long(с C++11) - Если тип
v— float, используется спецификатор преобразования%g - Если тип
v— double, используется спецификатор преобразования%lg - Если тип
v— long double, используется спецификатор преобразования%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) |
- Если функция преобразования не смогла преобразовать все поле, в
vсохраняется значение0. - Если тип
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 issue 23 и LWG issue 696, v оставалось неизменным, если произошла ошибка.
Перед разрешением LWG issue 221, строки, представляющие шестнадцатеричные целые числа (например, "0xA0"), отклонялись do_get(int) даже если они являются допустимым вводом для strtol, поскольку на втором этапе фильтровались символы 'X' и 'x'.
Перед разрешением LWG issue 1169, преобразование строки с отрицательным числом в целое без знака могло привести к нулю (поскольку значение, представленное строкой, было меньше, чем то, которое может представить целевой тип).
| Перед разрешением LWG issue 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/w/cpp/locale/num_get/get