Форум программистов, компьютерный форум CyberForum.ru

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

Восстановить пароль Регистрация
 
 
Whiteha
Программист
33 / 33 / 4
Регистрация: 08.07.2011
Сообщений: 190
Записей в блоге: 1
30.10.2013, 00:51     Универсальная функция получения числа через cin #1
Пытался написать универсальную функцию для гарантированного получения числа нужного типа, примерно так:

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, при нем двойка считывается как корректное значение, но поток не очищается от мусора, как я понимаю(а было бы не плохо все это непотребство отбраковывать и требовать повторный ввод).
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 03:13     Универсальная функция получения числа через cin #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() не работает. По-моему, у вас, один из вариантов, использует.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
MrGluck
Ворчун
Эксперт С++
 Аватар для MrGluck
4927 / 2670 / 243
Регистрация: 29.11.2010
Сообщений: 7,429
30.10.2013, 03:18     Универсальная функция получения числа через cin #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.
Whiteha
Программист
33 / 33 / 4
Регистрация: 08.07.2011
Сообщений: 190
Записей в блоге: 1
30.10.2013, 03:22  [ТС]     Универсальная функция получения числа через cin #23
Так, подтверждаю работоспособность последнего выложенного кода на своей машине, большое спасибо.
Никогда не дружил с "заскоками" iostream'ов, завтра на свежую голову поизучаю повнимательнее, что где было не так.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 03:29     Универсальная функция получения числа через cin #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, если по-русски, почему?
MrGluck
Ворчун
Эксперт С++
 Аватар для MrGluck
4927 / 2670 / 243
Регистрация: 29.11.2010
Сообщений: 7,429
30.10.2013, 03:30     Универсальная функция получения числа через cin #25
Whiteha, однако на бубунте работает. Пруф:
Универсальная функция получения числа через cin
MrGluck
Ворчун
Эксперт С++
 Аватар для MrGluck
4927 / 2670 / 243
Регистрация: 29.11.2010
Сообщений: 7,429
30.10.2013, 03:31     Универсальная функция получения числа через cin #26
del
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 03:50     Универсальная функция получения числа через cin #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.
Если по-русски, почему?
MrGluck
Ворчун
Эксперт С++
 Аватар для MrGluck
4927 / 2670 / 243
Регистрация: 29.11.2010
Сообщений: 7,429
30.10.2013, 03:59     Универсальная функция получения числа через cin #28
Цитата Сообщение от alsav22 Посмотреть сообщение
MrGluck, если по-русски, почему?
Оно кидает исключение
В описании http://www.cplusplus.com/reference/s...mbuf/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.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 04:07     Универсальная функция получения числа через cin #29
Цитата Сообщение от MrGluck Посмотреть сообщение
Видимо в старых компиляторах это не реализовано.
Не реализовано что?
MrGluck
Ворчун
Эксперт С++
 Аватар для MrGluck
4927 / 2670 / 243
Регистрация: 29.11.2010
Сообщений: 7,429
30.10.2013, 04:14     Универсальная функция получения числа через cin #30
Цитата Сообщение от alsav22 Посмотреть сообщение
Не реализовано что?
В новых компиляторах кидает исключение, из-за чего поток остается в "рабочем состоянии". В старых это не делает.

Добавлено через 5 минут
Это лишь предположение.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
30.10.2013, 04:17     Универсальная функция получения числа через cin #31
Цитата Сообщение от MrGluck Посмотреть сообщение
В новых компиляторах кидает исключение, из-за чего поток остается в "рабочем состоянии". В старых это не делает.
По какому поводу исключение? mingw 4.8.0 разве старый?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
30.10.2013, 04:28     Универсальная функция получения числа через cin
Еще ссылки по теме:

Функция cin.getline() C++
C++ Объясните пожалуйста как работают cin.good(), cin.sync(), cin.clear()
C++ Универсальная функция считывания переменных из бинарного файла

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

Или воспользуйтесь поиском по форуму:
MrGluck
Ворчун
Эксперт С++
 Аватар для MrGluck
4927 / 2670 / 243
Регистрация: 29.11.2010
Сообщений: 7,429
30.10.2013, 04:28     Универсальная функция получения числа через cin #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 разве старый?
у меня именно этот мингв исключение кидал.
Yandex
Объявления
30.10.2013, 04:28     Универсальная функция получения числа через cin
Ответ Создать тему
Опции темы

Текущее время: 11:30. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru