На форуме stackoverflow.com можно найти массу советов по тому как вывести имя элемента enum в поток, но практически все они весьма сложные и громоздкие. Однако эту задачу можно решить гораздо проще используя средства самого языка.
Описанный ниже прием я узнал из книги Б. Страуструпа "Дизайн и эволюция С++" (проведя до этого не один час в раздумьях).
Не многие знают, что для типа enum в С++ есть возможность перегружать операторы. Особенно полезно это свойство когда вы генерируете некоторое выражение, например, на SQL.
В данной статье я покажу как можно использовать эту возможность языка С++ на примере вывода имени элемента перечисления в поток.
Перед Вами работающий код, который отображает концепцию: мы используем перегрузку операторов ввода и вывода в поток, чтобы создавать элементы перечисления из строки в потоке и записывать строку в соответствии с элементом в поток. Все прекрасно, однако, можем ли мы как-то улучшить наше решение? Если поразмыслить, то в приведенном выше отрывке мы ограничены классами потоков библиотеки STL. Чтобы снять это ограничение необходимо всего лишь сделать перегрузку операторов шаблонной:
Теперь мы можем использовать, например, потоки из библиотеки Qt для ввода/вывода нашего перечисления. Но и это еще не все: мы также можем использовать перегрузку операторов +, -, * и всех остальных операторов языка C++ разрешенных к перегрузке в пользовательских типах!
Описанный ниже прием я узнал из книги Б. Страуструпа "Дизайн и эволюция С++" (проведя до этого не один час в раздумьях).
Не многие знают, что для типа enum в С++ есть возможность перегружать операторы. Особенно полезно это свойство когда вы генерируете некоторое выражение, например, на SQL.
В данной статье я покажу как можно использовать эту возможность языка С++ на примере вывода имени элемента перечисления в поток.
#include <iostream> #include <string> #include <stdexcept> enum SqlOp { Equal, NotEqual, Less, Greater, LessEqual, GreaterEqual }; inline std::istream& operator >> (std::istream& in, SqlOp& op) { std::string s; in >> s; if (s == "=") { op = Equal; } else if (s == "<>") { op = NotEqual; } else if (s == "<") { op = Less; } else if (s == ">") { op = Greater; } else if (s == "<=") { op = LessEqual; } else if (s == ">=") { op = GreaterEqual; } else { throw std::runtime_error("Incorrect input"); } return in; } inline std::ostream& operator << (std::ostream& out, const SqlOp& op) { switch(op) { case Equal: out << "="; break; case NotEqual: out << "<>"; break; case Less: out << "<"; break; case Greater: out << ">"; break; case LessEqual: out << "<="; break; case GreaterEqual: out << ">="; break; } return out; } int main(int argc, char * argv[]) { using namespace std; SqlOp op = Equal; while(cin) { try { cin >> op; } catch(std::exception& e) { cout << "error: " << e.what() << endl; return 1; } cout << op << ": " << static_cast<int>(op) << endl; } return 0; }
Перед Вами работающий код, который отображает концепцию: мы используем перегрузку операторов ввода и вывода в поток, чтобы создавать элементы перечисления из строки в потоке и записывать строку в соответствии с элементом в поток. Все прекрасно, однако, можем ли мы как-то улучшить наше решение? Если поразмыслить, то в приведенном выше отрывке мы ограничены классами потоков библиотеки STL. Чтобы снять это ограничение необходимо всего лишь сделать перегрузку операторов шаблонной:
enum SqlOp { Equal, NotEqual, Less, Greater, LessEqual, GreaterEqual }; template<typename _IStream> inline _IStream& operator >> (_IStream& in, SqlOp& op) { std::string s; in >> s; if (s == "=") { op = Equal; } else if (s == "<>") { op = NotEqual; } else if (s == "<") { op = Less; } else if (s == ">") { op = Greater; } else if (s == "<=") { op = LessEqual; } else if (s == ">=") { op = GreaterEqual; } else { throw std::runtime_error("Incorrect input"); } return in; } template<typename _OStream> inline _OStream& operator << (_OStream& out, const SqlOp& op) { switch(op) { case Equal: out << "="; break; case NotEqual: out << "<>"; break; case Less: out << "<"; break; case Greater: out << ">"; break; case LessEqual: out << "<="; break; case GreaterEqual: out << ">="; break; } return out; }
Теперь мы можем использовать, например, потоки из библиотеки Qt для ввода/вывода нашего перечисления. Но и это еще не все: мы также можем использовать перегрузку операторов +, -, * и всех остальных операторов языка C++ разрешенных к перегрузке в пользовательских типах!
Комментариев нет:
Отправить комментарий