Задача - создать шаблонную функцию, в которой в зависимости от типа
перечисления выбирается нужный индекс в контейнере 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 $