Перечисления

MQL5 API предоставляет возможность преобразовать значение перечисления в строку с помощью функции EnumToString. Готового обратного преобразования нет.

string EnumToString(enum value)

Функция преобразует значение (т.е. идентификатор переданного элемента) перечисления любого типа в строку.

Воспользуемся ею, чтобы решить одну из востребованных задач: узнать размер перечисления (сколько в нем элементов) и какие именно значения соответствуют всем элементам. Для этой цели реализуем в заголовочном файле EnumToArray.mqh специальную шаблонную функцию (благодаря шаблонному типу E она подойдет для любого перечисления):

template<typename E>
int EnumToArray(E dummyint &values[],
   const int start = INT_MIN,
   const int stop = INT_MAX)
{
   const static string t = "::";
   
   ArrayResize(values0);
   int count = 0;
   
   for(int i = starti < stop && !IsStopped(); i++)
   {
      E e = (E)i;
      if(StringFind(EnumToString(e), t) == -1)
      {
         ArrayResize(valuescount + 1);
         values[count++] = i;
      }
   }
   return count;
}

Принцип её действия основан на следующем. Поскольку перечисления в MQL5 хранятся в виде целых чисел типа int, поддерживается неявное приведение любого перечисления к (int), а также допускается явное приведение int обратно к любому типу перечисления. При этом, если значение соответствует одному из элементов перечисления, функция EnumToString возвращает строку с идентификатором этого элемента. В противном случае функция возвращает строку вида ENUM_TYPE::значение.

Таким образом, делая цикл по целым числам в приемлемом диапазоне и приводя их явно к типу перечисления, можно затем анализировать строку на выходе EnumToString на наличие '::', чтобы определить, является ли данное целое элементом перечисления или нет.

Использованная здесь функция StringFind будет представлена в следующей главе, как и другие функции работы со строками.

Для проверки концепции создадим скрипт ConversionEnum.mq5. В нем реализуем вспомогательную функцию process, которая будет вызвать шаблонную EnumToArray, сообщать количество элементов в перечислении и распечатывать полученный массив с соответствиями между элементами перечисления и их значениями.

template<typename E>
void process(E a)
{
  int result[];
  int n = EnumToArray(aresult0USHORT_MAX);
  Print(typename(E), " Count="n);
  for(int i = 0i < ni++)
  {
    Print(i" "EnumToString((E)result[i]), "="result[i]);
  }
}

В качестве перечисления для исследования возьмем встроенное перечисление с типами цен ENUM_APPLIED_PRICE. В функции OnStart для начала убедимся, что EnumToString производит строки по описанному выше принципу. Так, для элемента PRICE_CLOSE функция вернет строку "PRICE_CLOSE", а для значения (ENUM_APPLIED_PRICE)10, которое заведомо лежит вне диапазона, — "ENUM_APPLIED_PRICE::10".

void OnStart()
{
   PRT(EnumToString(PRICE_CLOSE));            // PRICE_CLOSE
   PRT(EnumToString((ENUM_APPLIED_PRICE)10)); // ENUM_APPLIED_PRICE::10
   
   process((ENUM_APPLIED_PRICE)0);
}

Далее вызовем функцию process для любого значения, приведенного к ENUM_APPLIED_PRICE (или переменной этого типа), и получим следующий результат:

ENUM_APPLIED_PRICE Count=7
0 PRICE_CLOSE=1
1 PRICE_OPEN=2
2 PRICE_HIGH=3
3 PRICE_LOW=4
4 PRICE_MEDIAN=5
5 PRICE_TYPICAL=6
6 PRICE_WEIGHTED=7

Здесь мы видим, что в перечислении определено 7 элементов, причем нумерация начинается не с 0, как обычно, а с 1 (PRICE_CLOSE). Знание значений, сопоставленных с элементами, позволяет в некоторых случаях оптимизировать написание алгоритмов.