Как последовательно перебрать перечисление? - страница 7

 
Комбинатор:

А как быть с нормальными именами которые в комментах?

Динамический ENUM - для внутреннего пользования, в окне настроек такие не показывают. Нормальные имена / комменты не оч нужны
 

Кстати, в mql препроцессоре ошибка, видимо.

#define i ##nt ll;

раскрывается в 'i nt ll;' и выдаёт ошибку:

'i nt' - undeclared identifier    t_t_t.mq4    50    1


По поводу комментариев в перечислении - по идее, они должны дёргаться до Си препроцессора. Поэтому даже если бы впихнуть комментарий удалось, то вряд ли бы он имел эффект. По-хорошему, нужно менять синтаксис (на _cmnt_, наример) и менять последовательность вызова Си препроцессора с препроцессором, который выдёргивает комменты. Перспективы таких реформ маловероятны, думаю ))

 
pavlick_:

Кстати, в mql препроцессоре ошибка, видимо.

раскрывается в 'i nt ll;' и выдаёт ошибку:

Где-то у Вас ошибка. Правильно он раскрывает: nt ll;
 
Alexander Puzanov:
Динамический ENUM - для внутреннего пользования, в окне настроек такие не показывают. Нормальные имена / комменты не оч нужны
Такой динамический енум можно запихнуть в гораздо более приглядную форму.
 

Прошлый метод требовал написания заготовок вручную под enum и функцию возвращающую массив значений. Решил разобраться и написать так, чтобы необходимость в этом отпала. Правда это нельзя скомпилировать на mql, отсутствуют макросы с переменным числом аргументов, но теоретически могут появиться. В общем получилось вот что:

// Выглядит страшно, да )). Но это универсальная заготовка
// Можно засунуть в какой-нибудь cpp_magic.h
//cpp_magic.h
#define EVAL(...) EVAL1024(__VA_ARGS__)
#define EVAL1024(...) EVAL512(EVAL512(__VA_ARGS__))
#define EVAL512(...) EVAL256(EVAL256(__VA_ARGS__))
#define EVAL256(...) EVAL128(EVAL128(__VA_ARGS__))
#define EVAL128(...) EVAL64(EVAL64(__VA_ARGS__))
#define EVAL64(...) EVAL32(EVAL32(__VA_ARGS__))
#define EVAL32(...) EVAL16(EVAL16(__VA_ARGS__))
#define EVAL16(...) EVAL8(EVAL8(__VA_ARGS__))
#define EVAL8(...) EVAL4(EVAL4(__VA_ARGS__))
#define EVAL4(...) EVAL2(EVAL2(__VA_ARGS__))
#define EVAL2(...) EVAL1(EVAL1(__VA_ARGS__))
#define EVAL1(...) __VA_ARGS__
#define SECOND(a, b, ...) b
#define FIRST(a, ...) a
#define CAT(a,b) a ## b
#define EMPTY()
#define DEFER1(m) m EMPTY()
#define DEFER2(m) m EMPTY EMPTY()()
#define DEFER3(m) m EMPTY EMPTY EMPTY()()()
#define DEFER4(m) m EMPTY EMPTY EMPTY EMPTY()()()()
#define IS_PROBE(...) SECOND(__VA_ARGS__, 0)
#define PROBE() ~, 1
#define NOT(x) IS_PROBE(CAT(_NOT_, x))
#define _NOT_0 PROBE()
#define BOOL(x) NOT(NOT(x))
#define HAS_ARGS(...) BOOL(FIRST(_END_OF_ARGUMENTS_ __VA_ARGS__)())
#define _END_OF_ARGUMENTS_() 0
#define IF_ELSE(condition) _IF_ELSE(BOOL(condition))
#define _IF_ELSE(condition) CAT(_IF_, condition)
#define _IF_1(...) __VA_ARGS__ _IF_1_ELSE
#define _IF_0(...)             _IF_0_ELSE
#define _IF_1_ELSE(...)
#define _IF_0_ELSE(...) __VA_ARGS__
#define MAP1(m, first, ...)          \
  m(first)                           \
  IF_ELSE(HAS_ARGS(__VA_ARGS__))(    \
  DEFER2(_MAP1)()(m, __VA_ARGS__)    \
  )()
#define _MAP1() MAP1
#define MAP2(m, first, second, ...)  \
  m(first, second)                   \
  IF_ELSE(HAS_ARGS(__VA_ARGS__))(    \
  DEFER2(_MAP2)()(m, __VA_ARGS__)    \
  )()
#define _MAP2() MAP2
// main.cpp
#include <stdio.h>
#include "cpp_magic.h"

#define CREATE_ENUM_HELPER_1(el, val)  el = val,
#define CREATE_ENUM_HELPER_2(el, val)  el,
#define CREATE_ENUM(name, ...)                                     \
  enum name{                                                       \
    EVAL( MAP2(CREATE_ENUM_HELPER_1, __VA_ARGS__) )                \
  };                                                               \
  unsigned get_##name##_array(int *ar){                            \
    int temp[] = {                                                 \
    EVAL( MAP2(CREATE_ENUM_HELPER_2, __VA_ARGS__) )                \
    };                                                             \
    if(ar != NULL)                                                 \
      for(unsigned i = 0;  i < sizeof(temp) / sizeof(int);  ++i){  \
        ar[i] = temp[i];                                           \
    }                                                              \
    return sizeof(temp) / sizeof(int);                             \
  };

CREATE_ENUM(enum1, q,1, e,3, t,65, z,90)
CREATE_ENUM(enum2, ww,100, ss,-3, dh,21)
struct S{
  CREATE_ENUM(enum3, q,871, e,213, t,226)
}s;

int main()
{
  int ar[100];

  printf("----enum1-----\n");
  get_enum1_array(ar);
  for(unsigned i = 0;  i < get_enum1_array(NULL);  ++ i)
    printf("%d\n", ar[i]);

  printf("----enum2-----\n");
  get_enum2_array(ar);
  for(unsigned i = 0;  i < get_enum2_array(NULL);  ++ i)
    printf("%d\n", ar[i]);

  printf("----enum3-----\n");
  s.get_enum3_array(ar);
  for(unsigned i = 0;  i < s.get_enum3_array(NULL);  ++ i)
    printf("%d\n", ar[i]);
}

Выхлоп printf:
 ----enum1-----
 1
 3
 65
 90
 ----enum2-----
 100
 -3
 21
 ----enum3-----
 871
 213

 226

// Сгенерированный код для emum1
// enum enum1{
//   q = 1,
//   e = 3,
//   t = 65,
//   z = 90,
// };
// unsigned get_enum1_array(int *ar){
//   int temp[] = { q, e, t, z, };
//   if(ar != NULL)
//     for(unsigned i = 0; i < sizeof(temp) / sizeof(int); ++i){
//       ar[i] = temp[i]; }
//   return sizeof(temp) / sizeof(int);
// };

Статья на эту тему http://jhnet.co.uk/articles/cpp_magic. Вообще, магии многовато, конечно. Но техника может сгодиться для широкого круга задач относящихся к препроцессорной кодогенерации.

C Pre-Processor Magic - Articles - Jhnet
  • jhnet.co.uk
The C Pre-Processor (CPP) is the somewhat basic macro system used by the C programming language to implement features such as and which allow very simple text-substitutions to be carried out at compile time. In this article we abuse the humble to implement if-statements and iteration. Before we begin, a disclaimer: these tricks, while perfectly...
 
Жесть ) но респект
 

Я с интересом читаю ветку, все очень круто с макросами. 

Только неясно, а зачем нужны эти танцы с enum? Можно привести практический пример?  

Про ТФ ясно, а еще? 

 
pavlick_:

Правда это нельзя скомпилировать на mql, отсутствуют макросы с переменным числом аргументов, но теоретически могут появиться.

Ну вот это ключевой момент.  В MQL5 макросы мало того, что с фиксированным числом аргументов, так ещё и это число ограничено 8.  Так что удастся сделать enum всего для 3 значений.

А насчёт теоретического появления, наверно быстрей появится штатная функция для парсинга enum.  Разработчики уже обещали родить что-нибудь.

 
Alexey Navoykov:

Ну вот это ключевой момент.  В MQL5 макросы мало того, что с фиксированным числом аргументов, так ещё и это число ограничено 8.  Так что удастся сделать enum всего для 3 значений.

А насчёт теоретического появления, наверно быстрей появится штатная функция для парсинга enum.  Разработчики уже обещали родить что-нибудь.

Итератора для перебора значений энумератора не планируется.
Используйте ранее предложенный способ перебора значений с использованием массива.
enum Enum
 {
  VAL_0,
  VAL_1,
  ...
 };

const Enum EnumValues[]={ VAL_0, VAL_1, ... };

for(uint i=0;i<ArraySize(EnumValues);i++)
   Print(EnumToString(EnumValues[i]));
 
Ilyas:
Итератора для перебора значений энумератора не планируется.
Используйте ранее предложенный способ перебора значений с использованием массива.
Выходит, что это тот же switch, но вид сбоку. То есть в любом случае потребуется поддерживать два списка: само перечисление и массив (кейсы от switch'a).