Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.80/5: Рейтинг темы: голосов - 5, средняя оценка - 4.80
sourcerer
Модератор
Эксперт CЭксперт С++
4963 / 2149 / 326
Регистрация: 20.02.2013
Сообщений: 5,582
Записей в блоге: 24
Завершенные тесты: 1
1

Как правильно реализовать проверку типа передаваемого аргумента в шаблонной функции?

03.12.2016, 13:55. Просмотров 894. Ответов 13
Метки нет (Все метки)

Доброго времени суток, уважаемые форумчане!

Пытаюсь реализовать проверку типа аргумента, передаваемого шаблонной функции. Использую функции из заголовочного файла type_traits.

Написал вот такой код:
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
52
53
54
55
56
57
58
59
#include <iostream>
#include <string>
#include <type_traits>
 
struct Person
{
    std::string full_name;  // фамилия имя отчество
    std::string address;    // домашний адрес
    std::string phone;      // телефон
    size_t age;             // возраст
 
    void show() const
    {
        std::cout
            << "\n"
            << full_name
            << "\n"
            << address
            << "\n"
            << phone
            << "\n"
            << age
            << "\n";
    }
};
 
template <typename T>
void promt_user_input_data_of_selected_field
    (
        const std::string message,
        T selected_field
    )
{
    std::cout << message;
 
    if ( std::is_same<T, std::string>::value || std::is_same<T, const std::string>::value )
    {
        while ( std::cin.get() != '\n' ) {} // очищаем поток
        std::getline( std::cin, selected_field );
    }
    else if ( std::is_same<T, size_t>::value )
        std::cin >> selected_field;
    else
        std::cin >> selected_field;
}
 
int main()
{
    Person pers;
 
    promt_user_input_data_of_selected_field( "Enter full name of student", pers.full_name );
    promt_user_input_data_of_selected_field( "Enter address of student", pers.address );
    promt_user_input_data_of_selected_field( "Enter phone number of student", pers.phone );
    promt_user_input_data_of_selected_field( "Enter age of student", pers.age );
 
    pers.show();
 
    return 0;
}
По непонятной мне причине программа упорно спотыкается на 39-й строке. Почему вообще происходит вход в ветку if? Неужели unsigned int приводится к std::string? С какой стати?

Скрин ошибки:
1
Миниатюры
Как правильно реализовать проверку типа передаваемого аргумента в шаблонной функции?  
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
03.12.2016, 13:55
Ответы с готовыми решениями:

Получение результата как аргумента, передаваемого по ссылке
Проблема в том, что мне надо получить значение функции через аргумент, через строковый аргумент. Я...

Как реализовать проверку типа переменной с помощью try/catch?
Здравствуйте! Я немножко не понял как тут, в С++ работают эти вещи. Вот мне нужно проверить...

Как лучше реализовать проверку аргумента?
Доброго времени суток всем. Подскажите, пожалуйста как правильней и лучше делать Есть 2 метода...

Лямбда выражение в качестве передаваемого аргумента функции
Добрый день! Подскажите пожалуйста, могу ли я в функциях библиотеки Qt использовать в качестве...

Junit тесты: как правильно реализовать проверку метода findAll?
Доброго времени суток, форумчане. Подскажите пожалуйста, как правильно реализовать проверку метода...

13
sourcerer
Модератор
Эксперт CЭксперт С++
4963 / 2149 / 326
Регистрация: 20.02.2013
Сообщений: 5,582
Записей в блоге: 24
Завершенные тесты: 1
03.12.2016, 14:45  [ТС] 2
Какой-то бред происходит:

Так - ожидаемое поведение.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <type_traits>
#include <iostream>
#include <string>
 
template <typename T>
void check_type( T )
{
    if ( std::is_unsigned<T>::value )
        std::cout << "It's unsigned integer.\n\n";
    else
        std::cout << "It's something else.\n\n";
}
 
int main()
{
    unsigned int uint = 23;
    std::string name = "Igor";
 
    check_type( uint );
    check_type( name );
 
    return 0;
}
Как правильно реализовать проверку типа передаваемого аргумента в шаблонной функции?


Так - ошибка компиляции.

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
#include <iostream>
#include <string>
 
template <typename T>
void check_type( T & t )
{
    if ( std::is_unsigned<T>::value ) {
        std::cout << "\nEnter an unsigned integer: ";
        std::cin >> t;
    }
 
    else {
        std::cout << "\nEnter a string: ";
        std::getline( std::cin, t );
    }
}
 
int main()
{
    unsigned int uint = 23;
    std::string name = "Igor";
 
    check_type( uint );
    std::cout << uint;
 
    check_type( name );
    std::cout << name;
}
Как правильно реализовать проверку типа передаваемого аргумента в шаблонной функции?

0
Croessmah
++Ͻ
15943 / 9055 / 1744
Регистрация: 27.09.2012
Сообщений: 22,292
Записей в блоге: 2
Завершенные тесты: 2
03.12.2016, 15:01 3
Лучший ответ Сообщение было отмечено gru74ik как решение

Решение

Цитата Сообщение от gru74ik Посмотреть сообщение
Почему вообще происходит вход в ветку if?
На самом деле всё просто. if работает в рантайме.
Но компилятору же нужно построить код для выполнения обоих веток.
Посему получается подобное:
C++
1
2
int x;
std::getline(std::cin, x);
согласись, что это бредовый код.
Собственно компилятору это тоже не нравится.
В C++17 появился if constexpr для решения подобных проблем.

По старому же ветвление на типах можно сделать чуть по-другому.
Сейчас накатаю.
1
DrOffset
11081 / 5936 / 1458
Регистрация: 30.01.2014
Сообщений: 9,549
03.12.2016, 15:04 4
Лучший ответ Сообщение было отмечено gru74ik как решение

Решение

Цитата Сообщение от Croessmah Посмотреть сообщение
Сейчас накатаю.
gru74ik, а я пока просто вот это тут оставлю: http://ru.cppreference.com/w/cpp/types/enable_if
1
03.12.2016, 15:04
Croessmah
++Ͻ
15943 / 9055 / 1744
Регистрация: 27.09.2012
Сообщений: 22,292
Записей в блоге: 2
Завершенные тесты: 2
03.12.2016, 15:10 5
Лучший ответ Сообщение было отмечено gru74ik как решение

Решение

На скорую руку (без enable_if):
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
namespace details
{
    template <typename T>
    void promt_user_input_data_of_selected_field_impl(T &value)
    {
        std::cin >> value;
    }
    
    
    template <>
    void promt_user_input_data_of_selected_field_impl<std::string>(std::string &value)
    {
        while ( std::cin.get() != '\n' ) {} // очищаем поток. А если до этого не было ввода, или символ '\n' уже был извлечен из потока, то мы пропустим введенную строку?
        std::getline( std::cin, value );
    }
}
 
 
 
 
 
 
template <typename T>
void promt_user_input_data_of_selected_field
    (
        const std::string message,
        T &selected_field
    )
{
    std::cout << message;
    ::details::promt_user_input_data_of_selected_field_impl<std::decay_t<T>>(selected_field);
}
1
GbaLog-
Любитель чаепитий
3203 / 1504 / 472
Регистрация: 24.08.2014
Сообщений: 5,274
Записей в блоге: 1
Завершенные тесты: 2
03.12.2016, 15:18 6
Лучший ответ Сообщение было отмечено gru74ik как решение

Решение

Как-то так:
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
#include <iostream>
 
template<typename _Tp>
void fooImpl( _Tp& value )
{
    std::cin >> value;
}
 
template<> void fooImpl<unsigned>( unsigned& value )
{
    std::cin >> value;
}
template<> void fooImpl<std::string>( std::string& value )
{
    std::getline(std::cin, value);
}
 
template<typename _Tp>
void foo( _Tp& value )
{
    fooImpl<std::decay_t<_Tp>>( value );
}
 
int main()
{
    unsigned valUInt;
    std::string name;
    foo( valUInt );
    foo( name );
}
Добавлено через 55 секунд
Ничего себе тут быстро всё.
Сейчас ещё и в плагиате меня начнут обвинять.
1
Croessmah
++Ͻ
15943 / 9055 / 1744
Регистрация: 27.09.2012
Сообщений: 22,292
Записей в блоге: 2
Завершенные тесты: 2
03.12.2016, 15:20 7
Цитата Сообщение от GbaLog- Посмотреть сообщение
Сейчас ещё и в плагиате меня начнут обвинять.
С чего бы? Такие шаблонокоды весьма распространены.
0
GbaLog-
03.12.2016, 15:24
  #8

Не по теме:

Цитата Сообщение от Croessmah Посмотреть сообщение
Такие шаблонокоды весьма распространены.
Ну ладно. Камень с души. :)

0
sourcerer
Модератор
Эксперт CЭксперт С++
4963 / 2149 / 326
Регистрация: 20.02.2013
Сообщений: 5,582
Записей в блоге: 24
Завершенные тесты: 1
03.12.2016, 15:42  [ТС] 9
Цитата Сообщение от Croessmah Посмотреть сообщение
В C++17 появился if constexpr для решения подобных проблем.
Всем огромное спасибо, но вот это - самый лучший ответ.
0
Croessmah
03.12.2016, 15:47
  #10

Не по теме:

gru74ik, только сам C++17 еще не появился. :D

0
sourcerer
03.12.2016, 15:50  [ТС]
  #11

Не по теме:

Цитата Сообщение от Croessmah Посмотреть сообщение
gru74ik, только сам C++17 еще не появился. :D
Уже скоро :)

0
Mr.X
Эксперт С++
3193 / 1720 / 435
Регистрация: 03.05.2010
Сообщений: 3,867
03.12.2016, 16:30 12
Вот у меня всегда были подозрения, что все эти сложные манипуляции с шаблонными типами нужны только там, где программа плохо спроектирована.
Почему сразу не сделать перегруженные функции для ввода данных?
Сначала смешали все в одну кучу, а потом как-то сложно отделяем зерна от плевел...
А что будет, если пользователь ошибется и вместо фамилии введет число?
По-моему, здесь лошадь поставлена впереди паровоза... Так-то при вводе данных программа должна управлять пользователем, а не наоборот...
1
rikimaru2013
03.12.2016, 16:37
  #13

Не по теме:

gru74ik, рад видеть, что вы вернулись к учебе С++ и продолжаете копать!!!

И избавляйтесь от таких информативных комментариев std::string phone; // телефон :p

0
sourcerer
Модератор
Эксперт CЭксперт С++
4963 / 2149 / 326
Регистрация: 20.02.2013
Сообщений: 5,582
Записей в блоге: 24
Завершенные тесты: 1
03.12.2016, 16:50  [ТС] 14
Цитата Сообщение от Mr.X Посмотреть сообщение
программа плохо спроектирована
Есть такое дело. Увы, я пока только учусь.

Добавлено через 5 минут
Mr.X, я что-то с этой задачкой до того вспотел (хотя она простая, как берёзовое полено), что попросту забыл про банальную перегрузку функций и зачем-то заморочился шаблонами. Спасибо, что напомнили

Добавлено через 1 минуту

Не по теме:

Цитата Сообщение от rikimaru2013 Посмотреть сообщение
И избавляйтесь от таких информативных комментариев
Это не мои. Это то, что осталось от кода ТСа )))

0
03.12.2016, 16:50
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
03.12.2016, 16:50

Фукнкция замены передаваемого аргумента
#include &lt;iostream&gt; #include &lt;cstring&gt; using namespace std; int replace (char * str, char...

Как исправить ошибку в XE7 при указании типа аргумента для функции?
Добрый день! Раньше писал сайты на php и Yii, решил освоить с++ и компоненты Среды разработки ...

Как правильно записать область определения аргумента при построении графика функции
Подскажите! Нужно построить график {x}^{2}-2/x-3. Как правильно записать область определения (-∞,0)...


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

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

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