Okay, let's go all preprocessor then :)
Intended way of use:
DEFINE_ENUM(DayOfWeek, (Monday)(Tuesday)(Wednesday)
(Thursday)(Friday)(Saturday)(Sunday))
int main(int argc, char* argv[])
{
DayOfWeek_t i = DayOfWeek::Monday;
std::cout << i << std::endl; // prints Monday
std::cin >> i >> std::endl; // reads the content of a string and
// deduce the corresponding enum value
}
Dark magic, involving the helpful Boost.Preprocessor library.
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#define DEFINE_ENUM_VAL_TO_STR(r, data, elem)
case BOOST_PP_CAT(data, BOOST_PP_CAT(::, elem)):
return out << BOOST_PP_STRINGIZE(elem);
#define DEFINE_ENUM_STR_TO_VAL(r, data, elem)
if (s == BOOST_PP_STRINGIZE(elem))
{ i = BOOST_PP_CAT(data, BOOST_PP_CAT(::, elem)) ; } else
#define DEFINE_ENUM(Name, Values)
struct Name {
enum type {
Invalid = 0,
BOOST_PP_SEQ_ENUM(Values)
};
};
typedef Name::type Name##_t;
std::ostream& operator<<(std::ostream& out, Name##_t i) {
switch(i) {
BOOST_PP_SEQ_FOR_EACH(DEFINE_ENUM_VAL_TO_STR, Name, Values)
default: return out << "~"; } }
std::istream& operator>>(std::istream& in, Name##_t& i) {
std::string s; in >> s;
BOOST_PP_SEQ_FOR_EACH(DEFINE_ENUM_STR_TO_VAL, Name, Values)
{ i = Name##::Invalid; } }
There are better ways, personally I use this little macro to store that all in a nicely sorted vector of pairs, static for the type, it also allows me to iterate through the values of the enum if the mood (or need) strikes :)
It's quite unfortunate though there is no support in the language for that. I would prefer if there was, enum are quite handy for codesets...
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…