Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.62/13: Рейтинг темы: голосов - 13, средняя оценка - 4.62
Программист
33 / 33 / 8
Регистрация: 08.07.2011
Сообщений: 190
Записей в блоге: 1
1

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

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

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

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
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
30.10.2013, 00:51
Ответы с готовыми решениями:

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

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

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

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

31
5498 / 4893 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 03:13 21
Author24 — интернет-сервис помощи студентам
Вот этот будет работать, 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Эксперт С++
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.10.2013, 03:18 22
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  [ТС] 23
Так, подтверждаю работоспособность последнего выложенного кода на своей машине, большое спасибо.
Никогда не дружил с "заскоками" iostream'ов, завтра на свежую голову поизучаю повнимательнее, что где было не так.
0
5498 / 4893 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 03:29 24
Вот ещё, добавил предварительнное восстановление потока, если ломается до вызова функции:
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Эксперт С++
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.10.2013, 03:30 25
Whiteha, однако на бубунте работает. Пруф:
Универсальная функция получения числа через cin
0
Форумчанин
Эксперт CЭксперт С++
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.10.2013, 03:31 26
del
0
5498 / 4893 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 03:50 27
Цитата Сообщение от 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Эксперт С++
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.10.2013, 03:59 28
Цитата Сообщение от 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
5498 / 4893 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 04:07 29
Цитата Сообщение от MrGluck Посмотреть сообщение
Видимо в старых компиляторах это не реализовано.
Не реализовано что?
0
Форумчанин
Эксперт CЭксперт С++
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.10.2013, 04:14 30
Цитата Сообщение от alsav22 Посмотреть сообщение
Не реализовано что?
В новых компиляторах кидает исключение, из-за чего поток остается в "рабочем состоянии". В старых это не делает.

Добавлено через 5 минут
Это лишь предположение.
0
5498 / 4893 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 04:17 31
Цитата Сообщение от MrGluck Посмотреть сообщение
В новых компиляторах кидает исключение, из-за чего поток остается в "рабочем состоянии". В старых это не делает.
По какому поводу исключение? mingw 4.8.0 разве старый?
0
Форумчанин
Эксперт CЭксперт С++
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
30.10.2013, 04:28 32
Цитата Сообщение от 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
30.10.2013, 04:28
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
30.10.2013, 04:28
Помогаю со студенческими работами здесь

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
32
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru