Aug 16, 2017
|
Задача - создать шаблонную функцию, в которой в зависимости от типа
перечисления выбирается нужный индекс в контейнере vector
. Попробуем решить
задачу в лоб, создадим 3 перечисления и выберем нужный индекс в шаблоне.
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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | #include <vector>
#include <iostream> // cout
struct PEOPLE {
enum {
PEOPLE_ID, // 0
FIRSTNAME, // 1
LASTNAME // 2
};
};
struct STUDENT {
enum {
LASTNAME, // 0
FIRSTNAME, // 1
SALARY, // 2
_ID, // 3
};
};
struct EMPLOYE {
enum {
LASTNAME, // 0
_ID, // 1
FIRSTNAME, // 2
SALARY // 3
};
};
typedef std::vector<std::string> t_item;
template <class T>
void printHuman(t_item item, T _type)
{
std::string salary = "0.00 $";
std::string human_id = "-1";
const bool isStudent = std::is_same<T, STUDENT>::value;
const bool isEmploye = std::is_same<T, EMPLOYE>::value;
// PEOPLE
if (std::is_same<T, PEOPLE>::value) {
human_id = item.at(PEOPLE::PEOPLE_ID);
}
// STUDENT || EMPLOYE
else if (isStudent || isEmploye) {
// Выбираем поле в зависимости от типа структуры
salary = item.at(T::SALARY);
human_id = item.at(T::_ID);
}
// Отобажаем на экране
std::cout << human_id
<< "\t\t"
<< item.at(T::FIRSTNAME)
<< "\t\t"
<< item.at(T::LASTNAME)
<< "\t\t"
<< salary
<< std::endl;
}
int main()
{
// Создаем людей разных типов
t_item vasya{"1", "Vasya", "Vasnetsov"}; // PEOPLE
t_item petya{"Иванов", "Petr", "10.00 $", "13"}; // STUDENT
t_item bjarne{"Бьёрн", "66", "Straustrup", "100 000.00 $"}; // EMPLOYE
// Выводим информацию о людях
printHuman(vasya, PEOPLE());
printHuman(petya, STUDENT());
printHuman(bjarne, EMPLOYE());
return 0;
}
|
Скомпилируем пример с добавлением C++11
.
$ g++ -std=c++11 main.cpp -o enum-example
main-bad.cpp: In instantiation of ‘void printHuman(t_item, T) [with T = PEOPLE; t_item = std::vector<std::__cxx11::basic_string<char> >]’:
main-bad.cpp:78:30: required from here
main-bad.cpp:55:14: error: ‘SALARY’ is not a member of ‘PEOPLE’
salary = item.at(T::SALARY);
^
main-bad.cpp:56:14: error: ‘_ID’ is not a member of ‘PEOPLE’
human_id = item.at(T::_ID);
^
Makefile:7: recipe for target 'bad' failed
make: *** [bad] Error 1
Получаем ошибку, т.к. подстановка типа перечисления PEOPLE
не имеет
атрибутов _ID
и SALARY
.
Что бы обойти эту проблему выведем тип с помощью std::conditional
.
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 | void printHuman(t_item item, T _type)
{
std::string salary = "0.00 $";
std::string human_id = "-1";
const bool isStudent = std::is_same<T, STUDENT>::value;
const bool isEmploye = std::is_same<T, EMPLOYE>::value;
// PEOPLE
if (std::is_same<T, PEOPLE>::value) {
human_id = item.at(PEOPLE::PEOPLE_ID);
}
// STUDENT || EMPLOYE
else if (isStudent || isEmploye) {
// Выбираем поле в зависимости от типа структуры
typedef std::conditional<isStudent, STUDENT, EMPLOYE> cond;
salary = item.at(cond::type::SALARY);
human_id = item.at(cond::type::_ID);
}
// Отобажаем на экране
std::cout << human_id
<< "\t\t"
<< item.at(T::FIRSTNAME)
<< "\t\t"
<< item.at(T::LASTNAME)
<< "\t\t"
<< salary
<< std::endl;
}
|
В результате программа скомпилируется без ошибок. Это происходит потому, что
conditional
реализует свой шаблон на базе только двух нужных нам enum’ов
(STUDENT
, EMPLOY
).
$ g++ -std=c++11 main.cpp -o enum-example
$ ./enum-example
1 Vasya Vasnetsov 0.00 $
13 Petr Иванов 10.00 $
66 Straustrup Бьёрн 100 000.00 $