In order to make my code shorter and easier to change I want to replace something like
enum{ E_AAA, E_BBB, E_CCC };
static const char *strings{\"AAA\", \"BBB
I am a bit late to the party but here is another suggestion.
It creates a strongly typed enum class, say MyEnumName and a companion static helper class Enumator.
It's bigger than previous answers as it has more features, e.g. stream operators for conversion from/to string.
Note that it relies on c++ 14 standard due to the use of index sequence.
Usage:
/* One line definition - no redundant info */
ENUM_DEFINE(WeekDay /*first item is enum name*/,
Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday);
/* works seemlessly with streams (good for logging) */
auto dayOne = WeekDay::Sunday;
std::cout << "day of week is: " << day_of_week;
/* explicit construction from string using WeekDay_enum companion class*/
auto dayTwo = Enumator::fromString("Tuesday");
/*Iterate over all enum values using Enumator companion class*/
std::cout << "Days of the week are:\n"
for (auto enumVal : Enumator::getValues()) {
std::cout << enumVal << "\n";
}
Source:
#include
#include
#include
#include
template
using isEnum = typename std::enable_if::value>::type;
template>
constexpr static int enumSize() {
return 0;
}
template>
inline static std::string getEnumStringValues() {
return "";
}
/*Enum companion class to hold the methods that can't be declared in an enum*/
template* = nullptr>
class Enumator
{
Enumator() = delete; /* prevents instantiation */
public:
constexpr static int size() {
return enumSize();
}
/* list of all enum values a string */
static auto const& getValuesStr()
{
static std::array values;
if (values[0].empty()) {
std::string valuesStr = getEnumStringValues();
std::stringstream ss(valuesStr);
for (auto& value : values) {
std::getline(ss, value, ',');
}
}
return values;
};
/* list of all enum values */
static auto const& getValues()
{
static std::array values{ make_array(std::make_index_sequence()) };
return values;
};
/* To/from string conversion */
constexpr static std::string const& toString(EnumType arg) {
return getValuesStr()[static_cast(arg)];
}
static EnumType fromString(std::string const& val)
{
/* Attempt at converting from string value */
auto const& strValues = getValuesStr();
for (unsigned int i = 0; i < strValues.size(); i++)
{
if (val == strValues[i])
{
return static_cast(i);
}
}
throw std::runtime_error("No matching enum value found for token: " + val);
}
private:
/* Helper method to initialize array of enum values */
template
static auto make_array(std::index_sequence)
{
return std::array{{static_cast(Idx)...}};
}
};
template* = nullptr>
inline std::istream& operator>> (std::istream& input, EnumType& arg)
{
std::string val;
input >> val;
arg = Enumator::fromString(val);
return input;
}
template* = nullptr>
inline std::ostream& operator<< (std::ostream& output, const EnumType& arg)
{
return output << Enumator::toString(arg);
}
#define ENUM_DEFINE(EnumName,...)\
\
enum class EnumName;\
\
template<>\
constexpr int enumSize() {\
/*Trick to get the number of enum members:*/\
/*dump all the enum values in an array and compute its size */\
enum EnumName { __VA_ARGS__ }; \
EnumName enumArray[]{ __VA_ARGS__ }; \
return sizeof(enumArray) / sizeof(enumArray[0]); \
}\
\
template<>\
inline std::string getEnumStringValues() { return #__VA_ARGS__; }\
\
enum class EnumName : int { __VA_ARGS__ }