Как преобразовать переменную типа enum в строку?
Как заставить printf показывать значения переменных типа enum? Например:
typedef enum {Linux, Apple, Windows} OS_type;
OS_type myOS = Linux;
и мне нужно что-то вроде
printenum(OS_type, "My OS is %s", myOS);
который должен показывать строку "Linux", а не целое число.
Я полагаю, сначала я должен создать индексированный массив строк строк. Но я не знаю, если это самый красивый способ сделать это. Это вообще возможно?
38 ответов
Спасибо Джеймс за ваше предложение. Это было очень полезно, поэтому я реализовал другой способ внести свой вклад.
#include <iostream>
#include <boost/preprocessor.hpp>
using namespace std;
#define X_DEFINE_ENUM_WITH_STRING_CONVERSIONS_TOSTRING_CASE(r, data, elem) \
case data::elem : return BOOST_PP_STRINGIZE(elem);
#define X_DEFINE_ENUM_WITH_STRING_CONVERSIONS_TOENUM_IF(r, data, elem) \
if (BOOST_PP_SEQ_TAIL(data) == \
BOOST_PP_STRINGIZE(elem)) return \
static_cast<int>(BOOST_PP_SEQ_HEAD(data)::elem); else
#define DEFINE_ENUM_WITH_STRING_CONVERSIONS(name, enumerators) \
enum class name { \
BOOST_PP_SEQ_ENUM(enumerators) \
}; \
\
inline const char* ToString(name v) \
{ \
switch (v) \
{ \
BOOST_PP_SEQ_FOR_EACH( \
X_DEFINE_ENUM_WITH_STRING_CONVERSIONS_TOSTRING_CASE, \
name, \
enumerators \
) \
default: return "[Unknown " BOOST_PP_STRINGIZE(name) "]"; \
} \
} \
\
inline int ToEnum(std::string s) \
{ \
BOOST_PP_SEQ_FOR_EACH( \
X_DEFINE_ENUM_WITH_STRING_CONVERSIONS_TOENUM_IF, \
(name)(s), \
enumerators \
) \
return -1; \
}
DEFINE_ENUM_WITH_STRING_CONVERSIONS(OS_type, (Linux)(Apple)(Windows));
int main(void)
{
OS_type t = OS_type::Windows;
cout << ToString(t) << " " << ToString(OS_type::Apple) << " " << ToString(OS_type::Linux) << endl;
cout << ToEnum("Windows") << " " << ToEnum("Apple") << " " << ToEnum("Linux") << endl;
return 0;
}
https://godbolt.org/z/c6rK5ErMc
ENUM(bfield,
one = 1,
two = 2,
four = 4,
eight = 8,
sixteen = 16,
sixteen2 = 32
);
ENUM(Enum,
one,
two,
four,
eight,
sixteen,
sixteen2
);
int main()
{
std::cout << "bfield " << enumToString(static_cast<bfield>(1 | 2 | 4)) << "\n";
std::cout << "isBitField " << isBitField<bfield> << "\n";
std::cout << "Enum " << enumToString(Enum::sixteen) << "\n";
std::cout << "isBitField " << isBitField<Enum> << "\n";
return 0;
}
Program returned: 0
bfield { one, two, four }
isBitField 1
Enum sixteen
isBitField 0
Я немного опоздал, но вот мое решение с использованием g++ и только стандартных библиотек. Я попытался свести к минимуму загрязнение пространства имен и устранить необходимость повторного ввода имен перечислений.
Заголовочный файл "my_enum.hpp":
#include <cstring>
namespace ENUM_HELPERS{
int replace_commas_and_spaces_with_null(char* string){
int i, N;
N = strlen(string);
for(i=0; i<N; ++i){
if( isspace(string[i]) || string[i] == ','){
string[i]='\0';
}
}
return(N);
}
int count_words_null_delim(char* string, int tot_N){
int i;
int j=0;
char last = '\0';
for(i=0;i<tot_N;++i){
if((last == '\0') && (string[i]!='\0')){
++j;
}
last = string[i];
}
return(j);
}
int get_null_word_offsets(char* string, int tot_N, int current_w){
int i;
int j=0;
char last = '\0';
for(i=0; i<tot_N; ++i){
if((last=='\0') && (string[i]!='\0')){
if(j == current_w){
return(i);
}
++j;
}
last = string[i];
}
return(tot_N); //null value for offset
}
int find_offsets(int* offsets, char* string, int tot_N, int N_words){
int i;
for(i=0; i<N_words; ++i){
offsets[i] = get_null_word_offsets(string, tot_N, i);
}
return(0);
}
}
#define MAKE_ENUM(NAME, ...) \
namespace NAME{ \
enum ENUM {__VA_ARGS__}; \
char name_holder[] = #__VA_ARGS__; \
int name_holder_N = \
ENUM_HELPERS::replace_commas_and_spaces_with_null(name_holder); \
int N = \
ENUM_HELPERS::count_words_null_delim( \
name_holder, name_holder_N); \
int offsets[] = {__VA_ARGS__}; \
int ZERO = \
ENUM_HELPERS::find_offsets( \
offsets, name_holder, name_holder_N, N); \
char* tostring(int i){ \
return(&name_holder[offsets[i]]); \
} \
}
Пример использования:
#include <cstdio>
#include "my_enum.hpp"
MAKE_ENUM(Planets, MERCURY, VENUS, EARTH, MARS)
int main(int argc, char** argv){
Planets::ENUM a_planet = Planets::EARTH;
printf("%s\n", Planets::tostring(Planets::MERCURY));
printf("%s\n", Planets::tostring(a_planet));
}
Это выведет:
MERCURY
EARTH
Вы должны определить все только один раз, ваше пространство имен не должно быть загрязнено, и все вычисления выполняются только один раз (остальное - просто поиск). Однако вы не получаете безопасность типов классов enum (они по-прежнему просто короткие целые числа), вы не можете присваивать значения перечислениям, вы должны определять перечисления там, где вы можете определить пространства имен (например, глобально).
Я не уверен, насколько хороша производительность на этом, или, если это хорошая идея (я изучил C до C++, так что мой мозг все еще работает таким образом). Если кто-то знает, почему это плохая идея, не стесняйтесь указывать на это.
Это 2017 но вопрос еще жив
Еще один способ:
#include <iostream>
#define ERROR_VALUES \
ERROR_VALUE(NO_ERROR, 0, "OK") \
ERROR_VALUE(FILE_NOT_FOUND, 1, "Not found") \
ERROR_VALUE(LABEL_UNINITIALISED, 2, "Uninitialized usage")
enum Error
{
#define ERROR_VALUE(NAME, VALUE, TEXT) NAME = VALUE,
ERROR_VALUES
#undef ERROR_VALUE
};
inline std::ostream& operator<<(std::ostream& os, Error err)
{
int errVal = static_cast<int>(err);
switch (err)
{
#define ERROR_VALUE(NAME, VALUE, TEXT) case NAME: return os << "[" << errVal << "]" << #NAME << ", " << TEXT;
ERROR_VALUES
#undef ERROR_VALUE
default:
// If the error value isn't found (shouldn't happen)
return os << errVal;
}
}
int main() {
std::cout << "Error: " << NO_ERROR << std::endl;
std::cout << "Error: " << FILE_NOT_FOUND << std::endl;
std::cout << "Error: " << LABEL_UNINITIALISED << std::endl;
return 0;
}
Выходы:
Error: [0]NO_ERROR, OK
Error: [1]FILE_NOT_FOUND, Not found
Error: [2]LABEL_UNINITIALISED, Uninitialized usage
Еще одно стандартно-компилируемое решение на основе препроцессора без зависимостей, которое будет генерировать constexpr.
to_string
Функция для данного перечисления (и не требует каких-либо изменений кода для существующего перечисления) находится здесь.
Применение:
#include "generate_to_string.hpp"
enum class test_enum
{
value1,
value2
};
GENERATE_TO_STRING(test_enum, value1, value2) // emits warning if not all values are listed
const char* foo(test_enum v)
{
return to_string(v);
}
Полный код, взятый из сути, для копирования и вставки:
// workaround for old msvc preprocessor:
// https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
#define ETS_EXP(x) x
#define ETS_CASE(e, x) \
case e::x: \
return #x;
#define ETS_FE_0(e)
#define ETS_FE_1(e, x) ETS_CASE(e, x)
#define ETS_FE_2(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_1(e, __VA_ARGS__))
#define ETS_FE_3(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_2(e, __VA_ARGS__))
#define ETS_FE_4(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_3(e, __VA_ARGS__))
#define ETS_FE_5(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_4(e, __VA_ARGS__))
#define ETS_FE_6(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_5(e, __VA_ARGS__))
#define ETS_FE_7(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_6(e, __VA_ARGS__))
#define ETS_FE_8(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_7(e, __VA_ARGS__))
#define ETS_FE_9(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_8(e, __VA_ARGS__))
#define ETS_FE_10(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_9(e, __VA_ARGS__))
#define ETS_FE_11(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_10(e, __VA_ARGS__))
#define ETS_FE_12(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_11(e, __VA_ARGS__))
#define ETS_FE_13(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_12(e, __VA_ARGS__))
#define ETS_FE_14(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_13(e, __VA_ARGS__))
#define ETS_FE_15(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_14(e, __VA_ARGS__))
#define ETS_FE_16(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_15(e, __VA_ARGS__))
#define ETS_FE_17(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_16(e, __VA_ARGS__))
#define ETS_FE_18(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_17(e, __VA_ARGS__))
#define ETS_FE_19(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_18(e, __VA_ARGS__))
#define ETS_FE_20(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_19(e, __VA_ARGS__))
#define ETS_FE_21(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_20(e, __VA_ARGS__))
#define ETS_FE_22(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_21(e, __VA_ARGS__))
#define ETS_FE_23(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_22(e, __VA_ARGS__))
#define ETS_FE_24(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_23(e, __VA_ARGS__))
#define ETS_FE_25(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_24(e, __VA_ARGS__))
#define ETS_FE_26(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_25(e, __VA_ARGS__))
#define ETS_FE_27(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_26(e, __VA_ARGS__))
#define ETS_FE_28(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_27(e, __VA_ARGS__))
#define ETS_FE_29(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_28(e, __VA_ARGS__))
#define ETS_FE_30(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_29(e, __VA_ARGS__))
#define ETS_FE_31(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_30(e, __VA_ARGS__))
#define ETS_FE_32(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_31(e, __VA_ARGS__))
#define ETS_FE_33(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_32(e, __VA_ARGS__))
#define ETS_FE_34(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_33(e, __VA_ARGS__))
#define ETS_FE_35(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_34(e, __VA_ARGS__))
#define ETS_FE_36(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_35(e, __VA_ARGS__))
#define ETS_FE_37(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_36(e, __VA_ARGS__))
#define ETS_FE_38(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_37(e, __VA_ARGS__))
#define ETS_FE_39(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_38(e, __VA_ARGS__))
#define ETS_FE_40(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_39(e, __VA_ARGS__))
#define ETS_FE_41(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_40(e, __VA_ARGS__))
#define ETS_FE_42(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_41(e, __VA_ARGS__))
#define ETS_FE_43(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_42(e, __VA_ARGS__))
#define ETS_FE_44(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_43(e, __VA_ARGS__))
#define ETS_FE_45(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_44(e, __VA_ARGS__))
#define ETS_FE_46(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_45(e, __VA_ARGS__))
#define ETS_FE_47(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_46(e, __VA_ARGS__))
#define ETS_FE_48(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_47(e, __VA_ARGS__))
#define ETS_FE_49(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_48(e, __VA_ARGS__))
#define ETS_FE_50(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_49(e, __VA_ARGS__))
#define ETS_FE_51(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_50(e, __VA_ARGS__))
#define ETS_FE_52(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_51(e, __VA_ARGS__))
#define ETS_FE_53(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_52(e, __VA_ARGS__))
#define ETS_FE_54(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_53(e, __VA_ARGS__))
#define ETS_FE_55(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_54(e, __VA_ARGS__))
#define ETS_FE_56(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_55(e, __VA_ARGS__))
#define ETS_FE_57(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_56(e, __VA_ARGS__))
#define ETS_FE_58(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_57(e, __VA_ARGS__))
#define ETS_FE_59(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_58(e, __VA_ARGS__))
#define ETS_FE_60(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_59(e, __VA_ARGS__))
#define ETS_FE_61(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_60(e, __VA_ARGS__))
#define ETS_FE_62(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_61(e, __VA_ARGS__))
#define ETS_FE_63(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_62(e, __VA_ARGS__))
#define ETS_FE_64(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_63(e, __VA_ARGS__))
#define ETS_FE_65(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_64(e, __VA_ARGS__))
#define ETS_FE_66(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_65(e, __VA_ARGS__))
#define ETS_FE_67(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_66(e, __VA_ARGS__))
#define ETS_FE_68(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_67(e, __VA_ARGS__))
#define ETS_FE_69(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_68(e, __VA_ARGS__))
#define ETS_FE_70(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_69(e, __VA_ARGS__))
#define ETS_FE_71(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_70(e, __VA_ARGS__))
#define ETS_FE_72(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_71(e, __VA_ARGS__))
#define ETS_FE_73(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_72(e, __VA_ARGS__))
#define ETS_FE_74(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_73(e, __VA_ARGS__))
#define ETS_FE_75(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_74(e, __VA_ARGS__))
#define ETS_FE_76(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_75(e, __VA_ARGS__))
#define ETS_FE_77(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_76(e, __VA_ARGS__))
#define ETS_FE_78(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_77(e, __VA_ARGS__))
#define ETS_FE_79(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_78(e, __VA_ARGS__))
#define ETS_FE_80(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_79(e, __VA_ARGS__))
#define ETS_FE_81(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_80(e, __VA_ARGS__))
#define ETS_FE_82(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_81(e, __VA_ARGS__))
#define ETS_FE_83(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_82(e, __VA_ARGS__))
#define ETS_FE_84(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_83(e, __VA_ARGS__))
#define ETS_FE_85(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_84(e, __VA_ARGS__))
#define ETS_FE_86(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_85(e, __VA_ARGS__))
#define ETS_FE_87(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_86(e, __VA_ARGS__))
#define ETS_FE_88(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_87(e, __VA_ARGS__))
#define ETS_FE_89(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_88(e, __VA_ARGS__))
#define ETS_FE_90(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_89(e, __VA_ARGS__))
#define ETS_FE_91(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_90(e, __VA_ARGS__))
#define ETS_FE_92(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_91(e, __VA_ARGS__))
#define ETS_FE_93(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_92(e, __VA_ARGS__))
#define ETS_FE_94(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_93(e, __VA_ARGS__))
#define ETS_FE_95(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_94(e, __VA_ARGS__))
#define ETS_FE_96(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_95(e, __VA_ARGS__))
#define ETS_FE_97(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_96(e, __VA_ARGS__))
#define ETS_FE_98(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_97(e, __VA_ARGS__))
#define ETS_FE_99(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_98(e, __VA_ARGS__))
#define ETS_FE_100(e, x, ...) ETS_CASE(e, x) ETS_EXP(ETS_FE_99(e, __VA_ARGS__))
#define ETS_MATCH_ARGS( \
ign0, ign1, ign2, ign3, ign4, ign5, ign6, ign7, ign8, ign9, ign10, ign11, \
ign12, ign13, ign14, ign15, ign16, ign17, ign18, ign19, ign20, ign21, \
ign22, ign23, ign24, ign25, ign26, ign27, ign28, ign29, ign30, ign31, \
ign32, ign33, ign34, ign35, ign36, ign37, ign38, ign39, ign40, ign41, \
ign42, ign43, ign44, ign45, ign46, ign47, ign48, ign49, ign50, ign51, \
ign52, ign53, ign54, ign55, ign56, ign57, ign58, ign59, ign60, ign61, \
ign62, ign63, ign64, ign65, ign66, ign67, ign68, ign69, ign70, ign71, \
ign72, ign73, ign74, ign75, ign76, ign77, ign78, ign79, ign80, ign81, \
ign82, ign83, ign84, ign85, ign86, ign87, ign88, ign89, ign90, ign91, \
ign92, ign93, ign94, ign95, ign96, ign97, ign98, ign99, ign100, name, ...) \
name
#define ETS_FOR_EACH(e, ...) \
ETS_EXP(ETS_MATCH_ARGS( \
_0, __VA_ARGS__, ETS_FE_100, ETS_FE_99, ETS_FE_98, ETS_FE_97, \
ETS_FE_96, ETS_FE_95, ETS_FE_94, ETS_FE_93, ETS_FE_92, ETS_FE_91, \
ETS_FE_90, ETS_FE_89, ETS_FE_88, ETS_FE_87, ETS_FE_86, ETS_FE_85, \
ETS_FE_84, ETS_FE_83, ETS_FE_82, ETS_FE_81, ETS_FE_80, ETS_FE_79, \
ETS_FE_78, ETS_FE_77, ETS_FE_76, ETS_FE_75, ETS_FE_74, ETS_FE_73, \
ETS_FE_72, ETS_FE_71, ETS_FE_70, ETS_FE_69, ETS_FE_68, ETS_FE_67, \
ETS_FE_66, ETS_FE_65, ETS_FE_64, ETS_FE_63, ETS_FE_62, ETS_FE_61, \
ETS_FE_60, ETS_FE_59, ETS_FE_58, ETS_FE_57, ETS_FE_56, ETS_FE_55, \
ETS_FE_54, ETS_FE_53, ETS_FE_52, ETS_FE_51, ETS_FE_50, ETS_FE_49, \
ETS_FE_48, ETS_FE_47, ETS_FE_46, ETS_FE_45, ETS_FE_44, ETS_FE_43, \
ETS_FE_42, ETS_FE_41, ETS_FE_40, ETS_FE_39, ETS_FE_38, ETS_FE_37, \
ETS_FE_36, ETS_FE_35, ETS_FE_34, ETS_FE_33, ETS_FE_32, ETS_FE_31, \
ETS_FE_30, ETS_FE_29, ETS_FE_28, ETS_FE_27, ETS_FE_26, ETS_FE_25, \
ETS_FE_24, ETS_FE_23, ETS_FE_22, ETS_FE_21, ETS_FE_20, ETS_FE_19, \
ETS_FE_18, ETS_FE_17, ETS_FE_16, ETS_FE_15, ETS_FE_14, ETS_FE_13, \
ETS_FE_12, ETS_FE_11, ETS_FE_10, ETS_FE_9, ETS_FE_8, ETS_FE_7, \
ETS_FE_6, ETS_FE_5, ETS_FE_4, ETS_FE_3, ETS_FE_2, ETS_FE_1, \
ETS_FE_0)(e, __VA_ARGS__))
#define GENERATE_TO_STRING(enum_type, ...) \
constexpr const char* to_string(enum_type val) \
{ \
switch (val) \
{ \
ETS_FOR_EACH(enum_type, __VA_ARGS__) \
} \
return "<unknown>"; \
}
Мы надеемся, что встроенное в C++ решение для отражения, которое управляет ими всеми, наконец попадет в C++26 (теперь мы знаем, что этого не произойдет, как в C++23).
XMACROS
xmacros.h:
#ifdef XDEF
// name
XDEF(Linux)
XDEF(Apple)
XDEF(Windows)
#undef XDEF
#endif
код:
typedef enum {
#define XDEF(n) n,
#include "xmacros.h"
} OS_type;
static const char* OS_name[] = {
#define XDEF(n) #n,
#include "xmacros.h"
};
OS_type myOS = Linux;
printf("%s\n", OS_name[myOS]);
enum class COLOR
{
RED,
BLUE
};
class Test
{
public:
string getColorStr( COLOR ecolor )
{
return _typeStr.find( ecolor )->second;
}
private:
static map<COLOR,string> _typeStr;
};
//于海洋
map<COLOR,string> Test:: _typeStr = {
{ COLOR::RED, "red"},
{ COLOR::BLUE, "blue"}
};
int main()
{
Test t;
std::cout << t.getColorStr( COLOR::BLUE ) << std::endl;
}
Я добавил один ответ, который не поддерживал значения перечисления, теперь добавил поддержку, которая также поддерживает присвоение значения перечисления. Как и в предыдущем решении, в этом используется минимум определения магии.
Вот заголовочный файл:
#pragma once
#include <string>
#include <map>
#include <regex>
template <class Enum>
class EnumReflect
{
public:
static const char* getEnums() { return ""; }
};
//
// Just a container for each enumeration type.
//
template <class Enum>
class EnumReflectBase
{
public:
static std::map<std::string, int> enum2int;
static std::map<int, std::string> int2enum;
static void EnsureEnumMapReady( const char* enumsInfo )
{
if (*enumsInfo == 0 || enum2int.size() != 0 )
return;
// Should be called once per each enumeration.
std::string senumsInfo(enumsInfo);
std::regex re("^([a-zA-Z_][a-zA-Z0-9_]+) *=? *([^,]*)(,|$) *"); // C++ identifier to optional " = <value>"
std::smatch sm;
int value = 0;
for (; regex_search(senumsInfo, sm, re); senumsInfo = sm.suffix(), value++)
{
string enumName = sm[1].str();
string enumValue = sm[2].str();
if (enumValue.length() != 0)
value = atoi(enumValue.c_str());
enum2int[enumName] = value;
int2enum[value] = enumName;
}
}
};
template <class Enum>
std::map<std::string, int> EnumReflectBase<Enum>::enum2int;
template <class Enum>
std::map<int, std::string> EnumReflectBase<Enum>::int2enum;
#define DECLARE_ENUM(name, ...) \
enum name { __VA_ARGS__ }; \
template <> \
class EnumReflect<##name>: public EnumReflectBase<##name> { \
public: \
static const char* getEnums() { return #__VA_ARGS__; } \
};
/*
Basic usage:
Declare enumeration:
DECLARE_ENUM( enumName,
enumValue1,
enumValue2,
enumValue3 = 5,
// comment
enumValue4
);
Conversion logic:
From enumeration to string:
printf( EnumToString(enumValue3).c_str() );
From string to enumeration:
enumName value;
if( !StringToEnum("enumValue4", value) )
printf("Conversion failed...");
*/
//
// Converts enumeration to string, if not found - empty string is returned.
//
template <class T>
std::string EnumToString(T t)
{
EnumReflect<T>::EnsureEnumMapReady(EnumReflect<T>::getEnums());
auto& int2enum = EnumReflect<T>::int2enum;
auto it = int2enum.find(t);
if (it == int2enum.end())
return "";
return it->second;
}
//
// Converts string to enumeration, if not found - false is returned.
//
template <class T>
bool StringToEnum(const char* enumName, T& t)
{
EnumReflect<T>::EnsureEnumMapReady(EnumReflect<T>::getEnums());
auto& enum2int = EnumReflect<T>::enum2int;
auto it = enum2int.find(enumName);
if (it == enum2int.end())
return false;
t = (T) it->second;
return true;
}
А вот пример тестового приложения:
DECLARE_ENUM(TestEnum,
ValueOne,
ValueTwo,
ValueThree = 5,
ValueFour = 7
);
DECLARE_ENUM(TestEnum2,
ValueOne2 = -1,
ValueTwo2,
ValueThree2 = -4,
ValueFour2
);
void main(void)
{
string sName1 = EnumToString(ValueOne);
string sName2 = EnumToString(ValueTwo);
string sName3 = EnumToString(ValueThree);
string sName4 = EnumToString(ValueFour);
TestEnum t1, t2, t3, t4, t5 = ValueOne;
bool b1 = StringToEnum(sName1.c_str(), t1);
bool b2 = StringToEnum(sName2.c_str(), t2);
bool b3 = StringToEnum(sName3.c_str(), t3);
bool b4 = StringToEnum(sName4.c_str(), t4);
bool b5 = StringToEnum("Unknown", t5);
string sName2_1 = EnumToString(ValueOne2);
string sName2_2 = EnumToString(ValueTwo2);
string sName2_3 = EnumToString(ValueThree2);
string sName2_4 = EnumToString(ValueFour2);
TestEnum2 t2_1, t2_2, t2_3, t2_4, t2_5 = ValueOne2;
bool b2_1 = StringToEnum(sName2_1.c_str(), t2_1);
bool b2_2 = StringToEnum(sName2_2.c_str(), t2_2);
bool b2_3 = StringToEnum(sName2_3.c_str(), t2_3);
bool b2_4 = StringToEnum(sName2_4.c_str(), t2_4);
bool b2_5 = StringToEnum("Unknown", t2_5);
Обновленная версия того же заголовочного файла будет храниться здесь:
https://github.com/tapika/cppscriptcore/blob/master/SolutionProjectModel/EnumReflect.h