Comments 14
Я писал очень похожую статью habrahabr.ru/post/236403 но у моего метода тоже есть проблемы
Вот еще одна реализация github.com/aantron/better-enums там ограничение только на включение внутрь класса. тем не менее очень хорошо сделана в том числе и compile time преобразования.
Вот еще одна реализация github.com/aantron/better-enums там ограничение только на включение внутрь класса. тем не менее очень хорошо сделана в том числе и compile time преобразования.
0
Я использую метод на макросах. По сравнению с предложенным в статье, этот метод не имеет оверхеда, а также дает дополнительные возможности.
Кроме того, по списку можно делать практически все что угодно: объявлять другие типы, создавать функции/классы, делать сериализацию и т.п.
Недостаток — трудночитаемый код. Но мне кажется, это приемлемая цена за надежность.
// объявляем список
#define MY_ENUM_DESC \
EITM( vasya ) \
EITM( petya ) \
EITM( vova ) \
// генерируем enum
enum my_enum {
#define EITM(itm) itm,
MY_ENUM_DESC
#undef EITM
my_enum_max
};
// функция для получения строки
const char * my_enum_s(my_enum e) {
static const char * tbl[] = {
#define EITM(itm) #itm,
MY_ENUM_DESC
#undef EITM
"" };
return tbl[e];
}
Кроме того, по списку можно делать практически все что угодно: объявлять другие типы, создавать функции/классы, делать сериализацию и т.п.
Недостаток — трудночитаемый код. Но мне кажется, это приемлемая цена за надежность.
+2
Метод интересный, но очень уж громоздкий. Особенно с учётом того, что нумераторов в проекте могут быть десятки. И вот это:
на мой взгляд, большой недостаток. Будет море копи-пасты — ведь подобные группы из макроса, нумератора и функции придётся копи-пастить каждый тип (засунуть под один макрос эти три штуки я особо не представляю как).
Недостаток — трудночитаемый код. Но мне кажется, это приемлемая цена за надежность
на мой взгляд, большой недостаток. Будет море копи-пасты — ведь подобные группы из макроса, нумератора и функции придётся копи-пастить каждый тип (засунуть под один макрос эти три штуки я особо не представляю как).
+1
Если много enum-ов, требующих рефлексии, то да, громоздко.
Метод на макросах лучше применять не часто. По моему опыту, даже крупные проекты имеют не более 5 таких списков.
Кстати, на макросах — это даже не рефлексия. Это больше похоже на мета программирование. enum — это порождение списка и лишь малая часть возможностей.
Например, в своем проекте я сделал список таблиц, которые читаются из sqlite базы. Для каждой таблицы создаются свои классы обработки (по списку инстанцируются шаблоны), всего 8 мест генерации. Добавляя в список новую таблицу, я экономлю кучу времени на написании оснастки этой таблицы — весь код генерирует за меня компилятор.
Метод на макросах лучше применять не часто. По моему опыту, даже крупные проекты имеют не более 5 таких списков.
Кстати, на макросах — это даже не рефлексия. Это больше похоже на мета программирование. enum — это порождение списка и лишь малая часть возможностей.
Например, в своем проекте я сделал список таблиц, которые читаются из sqlite базы. Для каждой таблицы создаются свои классы обработки (по списку инстанцируются шаблоны), всего 8 мест генерации. Добавляя в список новую таблицу, я экономлю кучу времени на написании оснастки этой таблицы — весь код генерирует за меня компилятор.
0
Да. Я работал в компании, где тоже в одном месте такой приём использовался. Сильный механизм, который, тем не менее, стоит использовать не больше нескольких раз в проекте — очень уж громоздкий.
На самом деле, на мой взгляд, подобные ходули — так же как 90% извращений на шаблонно-темплейтной чёрной магии в С++ — возникают потому, что нет нормальной возможности редактирования AST программы на этапе компиляции. Нужен полноценный язык (скорее всего — функциональный) с отладчиком — для выполнения кодогенерации для С++. Задача очень непростая (прежде всего потому, что требуется сохранить читабельность runtime-кода), но, на мой взгляд, рано или поздно придётся это сделать — иначе язык утонет в разнотипных шаблонных конструкциях.
О необходимости возможности редактирования AST говорят такие ребята, как Эрик Ниблер (один из экспертов в С++, я как раз тут эту мысль встретил и заболел ею). Эту штуку я обсуждал ещё позже с ребятами вот тут — как продолжение дискуссии…
Вы не встречали нигде подобных обсуждений? Интересно было бы глянуть что ещё люди думают по этому поводу.
На самом деле, на мой взгляд, подобные ходули — так же как 90% извращений на шаблонно-темплейтной чёрной магии в С++ — возникают потому, что нет нормальной возможности редактирования AST программы на этапе компиляции. Нужен полноценный язык (скорее всего — функциональный) с отладчиком — для выполнения кодогенерации для С++. Задача очень непростая (прежде всего потому, что требуется сохранить читабельность runtime-кода), но, на мой взгляд, рано или поздно придётся это сделать — иначе язык утонет в разнотипных шаблонных конструкциях.
О необходимости возможности редактирования AST говорят такие ребята, как Эрик Ниблер (один из экспертов в С++, я как раз тут эту мысль встретил и заболел ею). Эту штуку я обсуждал ещё позже с ребятами вот тут — как продолжение дискуссии…
Вы не встречали нигде подобных обсуждений? Интересно было бы глянуть что ещё люди думают по этому поводу.
0
Статья безусловно получилась. Даже независимо от практического результата вышло очень изящно, просто приятно почитать.
+1
Рекомендую сделать header-only решение.
0
Я так и не понял, зачем нужен
val_t
и пляски вокруг него, при том что и без этого все отлично работает ( о чем я писал еще 4 года назад)std::vector<std::string> parse(const char* args);
template<typename T, typename ...Ts>
std::map<T, std::string> make_map(const char* text, Ts... args)
{
std::vector<T> keys{args...};
std::vector<std::string> vals = parse(text);
auto k = keys.cbegin();
auto v = vals.cbegin();
std::map<T, std::string> r;
for (; k != keys.cend(); k++, v++) {
r.emplace(*k, *v);
}
return r;
}
#define ENUM(name, ...) \
enum name \
{ \
__VA_ARGS__ \
}; \
static std::string to_string(const name v) { \
static std::map<name, std::string> m {make_map<name>(#__VA_ARGS__, __VA_ARGS__)};\
return m.at(v); \
}
0
В вашей версии нельзя присваивать произвольные значения константам перечисления.
0
Почему же?
0
Допустим, если я допишу A=8 в ваш пример с ideone, то получаем ошибку компиляции:
prog.cpp: In static member function 'static std::string X::to_string(X::Y)':
prog.cpp:60:13: error: lvalue required as left operand of assignment
ENUM(Y,A=8,B,C)
^
0
Ещё есть способ, вместо enuma использовать структуру со статическими членами:
Вызов не сильно отличается от enuma Nums:One, но вместо цифры мы передадим строку.
struct Nums
{
static const std:string One;
static const std:string Two;
};
const static const std:string Nums:One = "One";
const static const std:string Nums:Two = "Two";
Вызов не сильно отличается от enuma Nums:One, но вместо цифры мы передадим строку.
0
Sign up to leave a comment.
Добавляем рефлексию для перечислений (enum) в C++