Комментарии 14
Я писал очень похожую статью habrahabr.ru/post/236403 но у моего метода тоже есть проблемы
Вот еще одна реализация github.com/aantron/better-enums там ограничение только на включение внутрь класса. тем не менее очень хорошо сделана в том числе и compile time преобразования.
Вот еще одна реализация github.com/aantron/better-enums там ограничение только на включение внутрь класса. тем не менее очень хорошо сделана в том числе и compile time преобразования.
Я использую метод на макросах. По сравнению с предложенным в статье, этот метод не имеет оверхеда, а также дает дополнительные возможности.
Кроме того, по списку можно делать практически все что угодно: объявлять другие типы, создавать функции/классы, делать сериализацию и т.п.
Недостаток — трудночитаемый код. Но мне кажется, это приемлемая цена за надежность.
// объявляем список
#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];
}
Кроме того, по списку можно делать практически все что угодно: объявлять другие типы, создавать функции/классы, делать сериализацию и т.п.
Недостаток — трудночитаемый код. Но мне кажется, это приемлемая цена за надежность.
Метод интересный, но очень уж громоздкий. Особенно с учётом того, что нумераторов в проекте могут быть десятки. И вот это:
на мой взгляд, большой недостаток. Будет море копи-пасты — ведь подобные группы из макроса, нумератора и функции придётся копи-пастить каждый тип (засунуть под один макрос эти три штуки я особо не представляю как).
Недостаток — трудночитаемый код. Но мне кажется, это приемлемая цена за надежность
на мой взгляд, большой недостаток. Будет море копи-пасты — ведь подобные группы из макроса, нумератора и функции придётся копи-пастить каждый тип (засунуть под один макрос эти три штуки я особо не представляю как).
Если много enum-ов, требующих рефлексии, то да, громоздко.
Метод на макросах лучше применять не часто. По моему опыту, даже крупные проекты имеют не более 5 таких списков.
Кстати, на макросах — это даже не рефлексия. Это больше похоже на мета программирование. enum — это порождение списка и лишь малая часть возможностей.
Например, в своем проекте я сделал список таблиц, которые читаются из sqlite базы. Для каждой таблицы создаются свои классы обработки (по списку инстанцируются шаблоны), всего 8 мест генерации. Добавляя в список новую таблицу, я экономлю кучу времени на написании оснастки этой таблицы — весь код генерирует за меня компилятор.
Метод на макросах лучше применять не часто. По моему опыту, даже крупные проекты имеют не более 5 таких списков.
Кстати, на макросах — это даже не рефлексия. Это больше похоже на мета программирование. enum — это порождение списка и лишь малая часть возможностей.
Например, в своем проекте я сделал список таблиц, которые читаются из sqlite базы. Для каждой таблицы создаются свои классы обработки (по списку инстанцируются шаблоны), всего 8 мест генерации. Добавляя в список новую таблицу, я экономлю кучу времени на написании оснастки этой таблицы — весь код генерирует за меня компилятор.
Да. Я работал в компании, где тоже в одном месте такой приём использовался. Сильный механизм, который, тем не менее, стоит использовать не больше нескольких раз в проекте — очень уж громоздкий.
На самом деле, на мой взгляд, подобные ходули — так же как 90% извращений на шаблонно-темплейтной чёрной магии в С++ — возникают потому, что нет нормальной возможности редактирования AST программы на этапе компиляции. Нужен полноценный язык (скорее всего — функциональный) с отладчиком — для выполнения кодогенерации для С++. Задача очень непростая (прежде всего потому, что требуется сохранить читабельность runtime-кода), но, на мой взгляд, рано или поздно придётся это сделать — иначе язык утонет в разнотипных шаблонных конструкциях.
О необходимости возможности редактирования AST говорят такие ребята, как Эрик Ниблер (один из экспертов в С++, я как раз тут эту мысль встретил и заболел ею). Эту штуку я обсуждал ещё позже с ребятами вот тут — как продолжение дискуссии…
Вы не встречали нигде подобных обсуждений? Интересно было бы глянуть что ещё люди думают по этому поводу.
На самом деле, на мой взгляд, подобные ходули — так же как 90% извращений на шаблонно-темплейтной чёрной магии в С++ — возникают потому, что нет нормальной возможности редактирования AST программы на этапе компиляции. Нужен полноценный язык (скорее всего — функциональный) с отладчиком — для выполнения кодогенерации для С++. Задача очень непростая (прежде всего потому, что требуется сохранить читабельность runtime-кода), но, на мой взгляд, рано или поздно придётся это сделать — иначе язык утонет в разнотипных шаблонных конструкциях.
О необходимости возможности редактирования AST говорят такие ребята, как Эрик Ниблер (один из экспертов в С++, я как раз тут эту мысль встретил и заболел ею). Эту штуку я обсуждал ещё позже с ребятами вот тут — как продолжение дискуссии…
Вы не встречали нигде подобных обсуждений? Интересно было бы глянуть что ещё люди думают по этому поводу.
Статья безусловно получилась. Даже независимо от практического результата вышло очень изящно, просто приятно почитать.
Рекомендую сделать header-only решение.
Я так и не понял, зачем нужен
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); \
}
В вашей версии нельзя присваивать произвольные значения константам перечисления.
Почему же?
Допустим, если я допишу 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)
^
Ещё есть способ, вместо 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, но вместо цифры мы передадим строку.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Добавляем рефлексию для перечислений (enum) в C++