Форум программистов, компьютерный форум, киберфорум
Наши страницы

С++ для начинающих

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

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

30.10.2013, 00:51. Просмотров 1009. Ответов 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
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
30.10.2013, 00:51
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Универсальная функция получения числа через cin (C++):

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

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

какую библиотеку надо подключать чтоб работала функция _getch() и функция cin.get() - C++
какую библиотеку надо подключать чтоб работала функция _getch() и функция cin.get()

Универсальная функция считывания переменных из бинарного файла - C++
Подскажите, написал запись в бинарный файл переменных, не могу считать, точнее функция должна быть универсальная под любой тип считывания ...

Универсальная функция для приема разных двумерных массивов - C++
В программе у меня много двумерных массивом разной размерности. Мне нужна одна функция (общая) чтобы работала на все массивы. Функция...

Защита от дурака при вводе текста с помощью: cin.get cin.clear cin.sync - C++
Доброго времени суток. На С++ учусь с недавних пор. Имеется стандартная &quot;защита от дурака&quot; на ввод. Не пойму предназначение cin.get() !=...

31
Whiteha
Программист
33 / 33 / 4
Регистрация: 08.07.2011
Сообщений: 190
Записей в блоге: 1
30.10.2013, 02:55  [ТС] #16
alsav22,
Ввод "abcd", аргумент шаблона long double, компилятор из gcc 4.7:
0
Миниатюры
Универсальная функция получения числа через cin  
alsav22
5428 / 4823 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 02:59 #17
Вы покажите, что вводите, и код, который используете. Я же на скрине показываю, что ввожу, и код показываю, который использую.

Добавлено через 1 минуту
У вас Linux?
0
MrGluck
Модератор
Эксперт CЭксперт С++
7496 / 4612 / 694
Регистрация: 29.11.2010
Сообщений: 12,626
30.10.2013, 03:02 #18
Цитата Сообщение от alsav22 Посмотреть сообщение
У вас Linux?
У меня в CB с мингв тоже вечный цикл. После добавления хедеров cstdlib, limits и ввода abcd - infinity loop как на скрине выше.
0
Whiteha
Программист
33 / 33 / 4
Регистрация: 08.07.2011
Сообщений: 190
Записей в блоге: 1
30.10.2013, 03:03  [ТС] #19
alsav22,
код getNum копия вашего
0
Миниатюры
Универсальная функция получения числа через cin   Универсальная функция получения числа через cin  
Whiteha
Программист
33 / 33 / 4
Регистрация: 08.07.2011
Сообщений: 190
Записей в блоге: 1
30.10.2013, 03:05  [ТС] #20
alsav22, да, Debian Wheezy i386

Добавлено через 1 минуту
MrGluck, вы уж простите что вам не отвечаю со скринами, думаю проблема зацикливания имеет одну общую причину.
0
alsav22
5428 / 4823 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 03:13 #21
Вот этот будет работать, 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
MrGluck
Модератор
Эксперт CЭксперт С++
7496 / 4612 / 694
Регистрация: 29.11.2010
Сообщений: 12,626
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
Whiteha
Программист
33 / 33 / 4
Регистрация: 08.07.2011
Сообщений: 190
Записей в блоге: 1
30.10.2013, 03:22  [ТС] #23
Так, подтверждаю работоспособность последнего выложенного кода на своей машине, большое спасибо.
Никогда не дружил с "заскоками" iostream'ов, завтра на свежую голову поизучаю повнимательнее, что где было не так.
0
alsav22
5428 / 4823 / 442
Регистрация: 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
MrGluck
Модератор
Эксперт CЭксперт С++
7496 / 4612 / 694
Регистрация: 29.11.2010
Сообщений: 12,626
30.10.2013, 03:30 #25
Whiteha, однако на бубунте работает. Пруф:
Универсальная функция получения числа через cin
0
MrGluck
Модератор
Эксперт CЭксперт С++
7496 / 4612 / 694
Регистрация: 29.11.2010
Сообщений: 12,626
30.10.2013, 03:31 #26
del
0
alsav22
5428 / 4823 / 442
Регистрация: 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
MrGluck
Модератор
Эксперт CЭксперт С++
7496 / 4612 / 694
Регистрация: 29.11.2010
Сообщений: 12,626
30.10.2013, 03:59 #28
Цитата Сообщение от alsav22 Посмотреть сообщение
MrGluck, если по-русски, почему?
Оно кидает исключение
В описании http://www.cplusplus.com/reference/streambuf/streambuf/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
alsav22
5428 / 4823 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 04:07 #29
Цитата Сообщение от MrGluck Посмотреть сообщение
Видимо в старых компиляторах это не реализовано.
Не реализовано что?
0
MrGluck
Модератор
Эксперт CЭксперт С++
7496 / 4612 / 694
Регистрация: 29.11.2010
Сообщений: 12,626
30.10.2013, 04:14 #30
Цитата Сообщение от alsav22 Посмотреть сообщение
Не реализовано что?
В новых компиляторах кидает исключение, из-за чего поток остается в "рабочем состоянии". В старых это не делает.

Добавлено через 5 минут
Это лишь предположение.
0
30.10.2013, 04:14
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
30.10.2013, 04:14
Привет! Вот еще темы с ответами:

Объясните пожалуйста как работают cin.good(), cin.sync(), cin.clear() - C++
Такая проблема: сдаю в вуза лабораторные по программированию, писал все сам, до этого c++ не изучал, поэтому возникали некоторые проблемы....

Функция getline(cin,.) - C++
Здравствуйте уважаемые программисты. По темам пробежался getline(), но чет не понял, проблема, почему при вводе данных о первом человеке...

Функция чтения cin.get - C++
Подскажите пожалуйста почему функция cin.get(str, len, '0') считывает не (len - 1) как должна, а (len - 2) символов ? #include &lt;iostream&gt;...

Функция cin.getline() - C++
Имеется часть кода: void EditName(Account &amp;acc) { delete acc.name; char nam; cout&lt;&lt;&quot;Введите новое имя: &quot;; ...


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.