Программист
33 / 33 / 8
Регистрация: 08.07.2011
Сообщений: 190
Записей в блоге: 1

Универсальная функция получения числа через cin

30.10.2013, 00:51. Показов 3322. Ответов 31
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Пытался написать универсальную функцию для гарантированного получения числа нужного типа, примерно так:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Функция для безопасного получения числа указанного типа,
// оставляет поток cin в корректном состояние, вроде бы гарантированно
template <class T = double>
T getNum(const T &min = numeric_limits<T>::lowest(),
         const T &max = numeric_limits<T>::max())
{
    if (max < min)
        throw string("Ошибка в аргументах getNum, минимум больше максимума");
 
    // Для очистки потока от некорректного состояния
    auto clear = []()
    {
        cin.clear();
        cin.ignore(numeric_limits<std::streamsize>::max(), '\n');
        //cin.sync();
        //cin.clear();
    };
 
    T num(0);
 
    do
    {
        cout << "Число должно быть больше или равно " << min
             << " и меньше или равно "                << max
             << endl;
 
        cin >> num;
 
        if (cin.fail() || cin.bad() || cin.eof())
        {
            clear();
            continue;
        }
 
    }
    while((static_cast<T>(num) < min) || (static_cast<T>(num) > max));
 
    clear();
 
    return static_cast<T>(num);
}
но что-то она не очень работает, точнее не обрабатывает как должна ввод текста вместо числа.
В частности при вызове с аргументом шаблона T = long double и рандовном набивание символов
num присваивается 0, а clear то ли не отрабатывает как надо, то ли еще что... в общем все работает не так.
Светлые умы, помогите довести до ума кто знает как

Добавлено через 18 минут
Кстати также некорректно обрабатывает ввод типа 2,,3, при нем двойка считывается как корректное значение, но поток не очищается от мусора, как я понимаю(а было бы не плохо все это непотребство отбраковывать и требовать повторный ввод).
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
30.10.2013, 00:51
Ответы с готовыми решениями:

Заполнить массив цифрами числа, считанного через cin
Здрасти, как ввести в массив int mMass число 12345 с помощью cin&gt;&gt;? Нужно чтобы в mMass записалась 1, в mMass записалась 2 .... и...

Как работает cin.peek, cin,get, cin.ignore, cin.clear?
Здравствуйте, товарищи и не товарищи!:) Я только начал изучать C++, а уже использую вещи, которые мне не понятны, и прошу объяснить, как...

Универсальная функция
1.Определим функцию K(n), которая определяет количество цифр в заданном натуральном числе n. 2. Вычисление квадрата целого числа m,...

31
5500 / 4895 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 03:13
Студворк — интернет-сервис помощи студентам
Вот этот будет работать, mingw почему-то не нравится cin.ignore(cin.rdbuf()->in_avail()) :
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <limits>
#include <cstdlib>
#include <windows.h>
using namespace std;
 
// Функция для безопасного получения числа указанного типа,
// оставляет поток cin в корректном состояние, вроде бы гарантированно
template <class T>
T getNum(const T &min = numeric_limits<T>::lowest(),
         const T &max = numeric_limits<T>::max())
{
    if (max < min)
        throw string("Ошибка в аргументах getNum, минимум больше максимума");
 
    T num(0);
    
    do
    {
        cout << "Число должно быть больше или равно " << min
                 << " и меньше или равно "            << max
                 << endl;
 
        while (!(cin >> num) || (cin.peek() != '\n'))
        {
            cin.clear();
            while (cin.get() != '\n');
            cout << "Ошибка ввода!" << endl;
        }
 
    } while (num < min || num > max);
 
    return num;
}
 
int main()
{
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);
 
    getNum(2, 6);
 
    system("pause");
    return 0;
}
Добавлено через 2 минуты
Потом нужно будет разобраться, что ему не нравится.

Добавлено через 1 минуту
MrGluck, в Linux, кстати, sync() не работает. По-моему, у вас, один из вариантов, использует.
1
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8217 / 5048 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.10.2013, 03:18
C++
1
2
3
4
5
6
while (!(cin >> num) || (cin.peek() != '\n'))
{
    cin.clear();
    cin.ignore(std::numeric_limits<streamsize>::max(), '\n');
    cout << "Ошибка ввода!" << endl;
}
cin.rdbuf()->in_avail(); возвращала 0

Добавлено через 3 минуты
in_avail() returns the number of chars it can see in the internal buffer, if any. Otherwise it calls showmanyc() to try to detect if chars are known to be available elsewhere, so a buffer fill request is guaranteed to succeed.

In turn, showmanyc() will return the number of chars it knows about, if any, or -1 if it knows that a read will fail, or 0 if it doesn't have a clue.
1
Программист
33 / 33 / 8
Регистрация: 08.07.2011
Сообщений: 190
Записей в блоге: 1
30.10.2013, 03:22  [ТС]
Так, подтверждаю работоспособность последнего выложенного кода на своей машине, большое спасибо.
Никогда не дружил с "заскоками" iostream'ов, завтра на свежую голову поизучаю повнимательнее, что где было не так.
0
5500 / 4895 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 03:29
Вот ещё, добавил предварительнное восстановление потока, если ломается до вызова функции:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <iostream>
#include <limits>
#include <cstdlib>
#include <windows.h>
using namespace std;
 
// Функция для безопасного получения числа указанного типа,
// оставляет поток cin в корректном состояние, вроде бы гарантированно
template <class T>
T getNum(const T &min = numeric_limits<T>::lowest(),
         const T &max = numeric_limits<T>::max())
{
    if (max < min)
        throw string("Ошибка в аргументах getNum, минимум больше максимума");
 
    T num(0);
 
     if (!cin)
     {
         cin.clear();
         cin.ignore(numeric_limits<streamsize>::max(), '\n');
     }
 
     do
    {
        cout << "Число должно быть больше или равно " << min
                 << " и меньше или равно "            << max
                 << endl;
 
        while (!(cin >> num) || (cin.peek() != '\n'))
        {
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
            cout << "Ошибка ввода!" << endl;
        }
 
    } while (num < min || num > max);
 
    return num;
}
 
int main()
{
    SetConsoleCP(1251);
    SetConsoleOutputCP(1251);
 
    getNum(2, 6);
 
    system("pause");
    return 0;
}
Добавлено через 2 минуты
Цитата Сообщение от MrGluck Посмотреть сообщение
cin.rdbuf()->in_avail(); возвращала 0
MrGluck, если по-русски, почему?
0
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8217 / 5048 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.10.2013, 03:30
Whiteha, однако на бубунте работает. Пруф:
0
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8217 / 5048 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.10.2013, 03:31
del
0
5500 / 4895 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 03:50
Цитата Сообщение от MrGluck Посмотреть сообщение
cin.rdbuf()->in_avail(); возвращала 0
Добавлено через 3 минуты
in_avail() returns the number of chars it can see in the internal buffer, if any. Otherwise it calls showmanyc() to try to detect if chars are known to be available elsewhere, so a buffer fill request is guaranteed to succeed.
In turn, showmanyc() will return the number of chars it knows about, if any, or -1 if it knows that a read will fail, or 0 if it doesn't have a clue.
Если по-русски, почему?
0
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8217 / 5048 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.10.2013, 03:59
Цитата Сообщение от alsav22 Посмотреть сообщение
MrGluck, если по-русски, почему?
Оно кидает исключение
В описании http://www.cplusplus.com/refer... /in_avail/
Basic guarantee: if an exception is thrown, the stream buffer is in a valid state (this also applies to standard derived classes).
Видимо в старых компиляторах это не реализовано.
Исключение выдает basic_ios::clear.
0
5500 / 4895 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 04:07
Цитата Сообщение от MrGluck Посмотреть сообщение
Видимо в старых компиляторах это не реализовано.
Не реализовано что?
0
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8217 / 5048 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.10.2013, 04:14
Цитата Сообщение от alsav22 Посмотреть сообщение
Не реализовано что?
В новых компиляторах кидает исключение, из-за чего поток остается в "рабочем состоянии". В старых это не делает.

Добавлено через 5 минут
Это лишь предположение.
0
5500 / 4895 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 04:17
Цитата Сообщение от MrGluck Посмотреть сообщение
В новых компиляторах кидает исключение, из-за чего поток остается в "рабочем состоянии". В старых это не делает.
По какому поводу исключение? mingw 4.8.0 разве старый?
0
Форумчанин
Эксперт CЭксперт С++
 Аватар для MrGluck
8217 / 5048 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.10.2013, 04:28
Цитата Сообщение от alsav22 Посмотреть сообщение
По какому поводу исключение? mingw 4.8.0 разве старый?
Исключение при перехвате выдает basic_ios::clear.
Нашел решение:
нужно добавить строку
C++
1
ios_base::sync_with_stdio(0);
и использовать
C++
1
2
cin.clear();
cin.ignore(cin.rdbuf()->in_avail(), '\n');
Добавлено через 3 минуты
А MS судя по всему с борландом синхронизируют любой поток и функция ios_base::sync_with_stdio() у них вообще не реализована толком.

Добавлено через 1 минуту
Цитата Сообщение от alsav22 Посмотреть сообщение
mingw 4.8.0 разве старый?
у меня именно этот мингв исключение кидал.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
30.10.2013, 04:28

Универсальная функция
Напишите пожалуйста прогу.Написать универсальную функцию для вычислениия заданных выражений.В main() обеспечить вызов этой функции и...

Универсальная функция
Здравствуйте! Прошу помощи. Можно сделать какую-нибудь универсальную функцию, которой можно было бы передавать массив заголовков столбцов и...

Универсальная функция Ajax
Хочу сделать универсальную функцию Ajax, но не получаеться получить ответ сразу, функция выполняется, а потом приходит ответ... Как...

Универсальная функция вывода
Господа, пытаюсь сделать функцию, которая напечатает массив, и будет универсальна для всех типов и одной структуры. Вот пока все мои...

Универсальная функция запросов в базу
Здравствуйте. Есть несколько мест в коде где идет 6-8 запросов в базу, запросы различные (select,insert,update,вызов процедур) запихать...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
32
Ответ Создать тему
Опции темы

Новые блоги и статьи
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
Создание формы заимствованного документа
Maks 03.08.2026
Задача: Необходимо создать собственную форму заимствованного документа. На форме должен быть реквизит "Покупатель", а также табличная часть со следующими реквизитами: - Расчетный счет покупателя. . .
Задача предоставления скидок покупателям
Maks 03.08.2026
Задача: В документе "Продажи" необходимо реализовать функционал предоставления скидок покупателям. Скидка должна автоматически рассчитываться и подставляться в соответствующее поле при выборе. . .
Почему SEO не начинается с ключевых слов: что проверить до написания текстов
Neotwalker 01.08.2026
Когда владельцу сайта предлагают заняться SEO, первым шагом часто становится сбор запросов и написание текстов. Логика кажется понятной: 1. Находим ключевые слова. 2. Добавляем их на. . .
Знание — сила: Доктрина интенциональности знаний, углубление в формулу
Hrethgir 01.08.2026
https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11957&stc=1&d=1785567302 Знаменитый афоризм Фрэнсиса Бэкона «Знание — сила» (Scientia potentia est) в массовой культуре принято понимать. . .
SUNO Ai - Река Без Дна
zorxor 31.07.2026
Автор стихотворения - астрофизик Марина Катыс Ссылка на сгенерированную музыкальную композицию: https:/ / suno. com/ song/ 6f6e5464-b290-4650-be6c-44c85f8d8013 Я говорю, что Время- как вода течет. . .
Из невошедшего на форум (диалог с ИИ-гугла)
zorxor 29.07.2026
А вот, что интересно, сказал мне ИИ-гугла: Этот текст — эмоциональный пост пользователя под ником zorxor на интернет-форуме (вероятно, посвященном мистике, непознанному или альтернативной науке). . . .
Был праздник вчера, а я и не знал.
kumehtar 28.07.2026
27. 07. 2026г. Intel Core 2 Duo исполнилось 20 лет Салют, шампанское, овации! :drink:
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru