// https://codereview.stackexchange.com/a/14315 #include #include #include #include #include // This is the type that will hold all the strings. // Each enumeration type will declare its own specialization. // Any enum that does not have a specialization will generate a compiler error // indicating that there is no definition of this variable (as there should be // be no definition of a generic version). template struct enumStrings { static std::vector data; }; // This is a utility type. // Created automatically. Should not be used directly. template struct enumRefHolder { T &enumVal; enumRefHolder(T &enumVal) : enumVal(enumVal) {} }; template struct enumConstRefHolder { T const &enumVal; enumConstRefHolder(T const &enumVal) : enumVal(enumVal) {} }; // The next two functions do the actual work of reading/writing an // enum as a string. template std::ostream &operator<<(std::ostream &str, enumConstRefHolder const &data) { return str << enumStrings::data[data.enumVal]; } template std::istream &operator>>(std::istream &str, enumRefHolder const &data) { std::string value; str >> value; // These two can be made easier to read in C++11 // using std::begin() and std::end() // auto begin = std::begin(enumStrings::data); auto end = std::end(enumStrings::data); auto find = std::find(begin, end, value); if (find != end) { data.enumVal = static_cast(std::distance(begin, find)); } else { throw std::invalid_argument(""); } return str; } // This is the public interface: // use the ability of function to deduce their template type without // being explicitly told to create the correct type of enumRefHolder template enumConstRefHolder enumToString(T const &e) { return enumConstRefHolder(e); } template enumRefHolder enumFromString(T &e) { return enumRefHolder(e); }