Я пытаюсь связать строки времени компиляции со значениями перечисления.
Вот моя первая попытка решить проблему:
EnumValue будет связывать время компиляции между строкой и перечислением
template<typename EnumType, int EnumIntValue, const char* EnumStrValue>
class EnumValue
{
public:
static const char* toString()
{
return EnumStrValue;
}
static const int toInt()
{
return EnumIntValue;
}
static EnumType get()
{
return static_cast<EnumType>(EnumIntValue);
}
};
EnumValueHolder будет содержать фактические значения как для строки, так и для enum.
Мне не нравится мой текущий дизайн, так как он все еще должен содержать указатель на строку. Я бы предпочел ассоциацию времени компиляции, но не смогу найти более элегантное решение
template<typename EnumType>
class EnumValueHolder
{
public:
EnumValueHolder()
{}
EnumValueHolder(const EnumType& value, const char* str)
: value(value), str(str)
{}
bool operator==(const EnumValueHolder<EnumType>& rhs) { return value == rhs.value; }
bool operator==(const EnumType& rhs)const { return value == rhs; }
operator EnumType()const
{
return value;
}
const char* toString()const
{
return str;
}
const int toInt()const
{
return static_cast<int>(value);
}
private:
EnumType value;
char const* str;
};
Маркос для простого обращения к типам перечислений и конструкции держателей перечислимых значений
#define ENUM_VALUE_TYPE(enumName, enumValue) \
EnumValue<enumName, (int)enumName::enumValue, str_##enumValue>
#define ENUM_VALUE_MAKE(enumName, enumValue) \
EnumValueHolder<enumName> { \
ENUM_VALUE_TYPE(enumName, enumValue)::get(), \
ENUM_VALUE_TYPE(enumName, enumValue)::toString() }
Ниже приведены мои тестовые примеры и примеры использования:
const char str_Apple[] = "Apple";
const char str_Orange[] = "Orange";
const char str_Pineapple[] = "Pineapple";
enum class EFruits
{
Apple,
Orange,
Pineapple
};
int main()
{
auto evApple = ENUM_VALUE_MAKE(EFruits, Apple);
std::cout << evApple.toString() << std::endl;
auto evOrange = ENUM_VALUE_MAKE(EFruits, Orange);
std::cout << evOrange.toString() << std::endl;
std::cout << "compare: " << (evApple == evOrange) << std::endl;
evApple = evOrange;
std::cout << evApple.toString() << std::endl;
auto myfruit = ENUM_VALUE_MAKE(EFruits, Pineapple);
std::cout << myfruit.toString() << std::endl;
switch (myfruit)
{
case EFruits::Apple:
std::cout << "Im an apple!" << std::endl;
break;
case EFruits::Orange:
std::cout << "Im an Orange!" << std::endl;
break;
case EFruits::Pineapple:
std::cout << "Im a Pineapple!" << std::endl;
break;
default:break;
}
}
Одна из целей - удалить глобальную строку:
const char str_Apple[] = "Apple";
const char str_Orange[] = "Orange";
const char str_Pineapple[] = "Pineapple";
Другой - создать макрос, который связывает перечисление со строкой
//Some crazy define that makes pairs of enum values and strings as
//compile time constants
#define DEFINE_ENUM_STRING(enumValue)\
enumValue, #enumValue
//Ideally, the macro would be used like this. This should be usable in any
//scope (global, namespace, class)
//with any access specifier (private, protected, public)
enum class EFruits
{
DEFINE_ENUM_STRING(Apple),
DEFINE_ENUM_STRING(Orange),
DEFINE_ENUM_STRING(Pineapple)
};
Итак, есть 2 основных вопроса:
1) Гарантирует ли этот текущий проект фактические константы времени для сопоставления перечисления со строкой?
2) Как определить макрос для строкового значения перечисления и объявить значение в классе перечисления, используя 1 строку?
Редактировать: это должно работать и компилироваться с msvs2017 на платформе win64 с использованием c ++ 11.
Спасибо.