Функция как параметр.

 

Можно ли на MQL5 реализовать код по смыслу похожий на следующий:

int arrayI[3]={1,2,3};
//+------------------------------------------------------------------+
void OnStart()
  {
   ForAll(todo1());
   ForAll(todo2());
  }
//+------------------------------------------------------------------+
void ForAll(void toDo(int))
  {
   for(int i=0;i<3;i++)
      toDo(arrayI[i]);
   ArrayPrint(arrayI);
  }
//---
void todo1(int &a)
  {
   Print("inc a");
   a++;
  }
//+------------------------------------------------------------------+
void todo2(int &a)
  {
   Print("mult a");
   a*=3;
  }
//+------------------------------------------------------------------+

Если да - как это сделать?

 

Переходите от функционального программирования к ООП.

todo1,todo2 - должны быть объектами.

В функццию ForAll() - передается указатель на нужный объект, и внутри него, у переданного объекта вызывается нужная функция.

Разумно todo1 и todo2 иметь либо экземплярами одного класса, либо экземплярами разных классов, наследников одного базового класса, а в функцию ForAll() - передается указатель именно на этот базовый класс. (Основная функция в базовом классе при этом может быть чисто виртуальной)

 
George Merts:

Переходите от функционального программирования к ООП.

todo1,todo2 - должны быть объектами.

В функццию ForAll() - передается указатель на нужный объект, и внутри него, у переданного объекта вызывается нужная функция.

Разумно todo1 и todo2 иметь либо экземплярами одного класса, либо экземплярами разных классов, наследников одного базового класса, а в функцию ForAll() - передается указатель именно на этот базовый класс. (Основная функция в базовом классе при этом может быть чисто виртуальной)

Спасибо за ответ - уже начал думать над ним (как что надумаю - возможно еще появятся вопросы).

Но все еще интересна сама принципиальная возможность указанного мной кода на MQL5. Ведь не всегда ООП удобно, например во все том же, указанном мной случае - нужно сделать 2 простые операции над массивом целых чисел. Создавать под это дело класс с методами (для разового использования причем).. ну как минимум это не первое что приходит в голову :)

 
BeforeFlight:

Можно ли на MQL5 реализовать код по смыслу похожий на следующий:

Если да - как это сделать?

Недавно появились указатели на функции. Вроде это то что нужно здесь. В документации примеры ищите.
 
BeforeFlight:
 

Но все еще интересна сама принципиальная возможность указанного мной кода на MQL5. Ведь не всегда ООП удобно, например во все том же, указанном мной случае - нужно сделать 2 простые операции над массивом целых чисел. Создавать под это дело класс с методами (для разового использования причем).. ну как минимум это не первое что приходит в голову :)

Ну, для разового использования - и указатели на функции тоже не нужны, проще выполнить нужные операции в цикле.

ООП-заморочки изначально проектируются для последующего многократного использования и поддержки. Если этого нет - то смысла в нем никакого.

 
BeforeFlight:

Можно ли на MQL5 реализовать код по смыслу похожий на следующий:

Если да - как это сделать?


Вроде как есть указатели на функции...  Но через ООП точно можно. 

 
George Merts:

Ну, для разового использования - и указатели на функции тоже не нужны, проще выполнить нужные операции в цикле.

ООП-заморочки изначально проектируются для последующего многократного использования и поддержки. Если этого нет - то смысла в нем никакого.

В общем случае согласен, но можно придумать такой пример, когда даже для одноразового использования оптимальней использовать указатель на функцию (они действительно есть, и это то что было нужно. Правда найти их сходу в справке не получилось..). Скажем, в рамках того же разбираемого примера - пусть у нас не 1-мерный, а 4х мерных массив, плюс нужно совершить не 2, а 4-5 "простых" операций с массивом. Тогда только для циклов уже нужно 16-20 строк (причем вложенных.. по мне так если в программе часто встречаются хотя бы 3 вложенных цикла - уже нужно что-то менять). Не говоря уже о том что все индексы этих циклов постоянно придется "за собой тащить". А о читаемости такой программы вообще можно не говорить.

Как уже выше сказал, с подсказок прокомментировавших, за что им спасибо, ответом был указатель на функцию. Для тех кто "наткнется" на эту тему в поисках ответа на похожий вопрос: в справке они находятся в разделе "Пользовательские типы" (что в общем логично.. после прочтения :))

https://www.mql5.com/ru/docs/basis/types/typedef

Также "доделаем" наш пример (изменений вовсе немного - нужно просто определить новый пользвательский тип, который по сути будет типом указателя на функцию):

typedef void(*overArrayI)(int &);
int arrayI[3]={1,2,3};
//+------------------------------------------------------------------+
void OnStart()
  {
   ForAll(todo1);
   ForAll(todo2);
  }
//+------------------------------------------------------------------+
void ForAll(overArrayI todo)
  {
   for(int i=0;i<3;i++)
      todo(arrayI[i]);
   ArrayPrint(arrayI);
  }
//---
void todo1(int &a)
  {
   Print("inc a");
   a++;
  }
//+------------------------------------------------------------------+
void todo2(int &a)
  {
   Print("mult a");
   a*=3;
  }
//+------------------------------------------------------------------+
Документация по MQL5: Основы языка / Типы данных / Пользовательские типы
Документация по MQL5: Основы языка / Типы данных / Пользовательские типы
  • www.mql5.com
Основы языка / Типы данных / Пользовательские типы - справочник по языку алгоритмического/автоматического трейдинга для MetaTrader 5
 
BeforeFlight:

Можно ли на MQL5 реализовать код по смыслу похожий на следующий:

Если да - как это сделать?


Можно попробовать через указатели на функции, но не знаю, поддерживает ли MQL5 передачу их в параметрах. Надо пробовать.

Попробуйте пример доработать.

typedef int (*TFunc)(int,int);

int add(int x,int y) 
{
    return(x+y); 
}

void OnStart()
{
    TFunc pfunc = add;   
    Print(pfunc(4,5));    
}

**

 

"Вести с полей" - не для всех функций реализованы указатели, как я понял. Но для простых структур вроде работают - уже хорошо.


И еще парочка вопросов немного не по теме, но к чему их плодить:

1. В отредактированном, рабочем, примере видно, что функции todo1 и todo2 объявляются и описываются как обычные функции, но это описание по сути излишнее - мы ведь используем их только раз, плюс к этому они "просты как бревно". Причем просты настолько, что даже строка с объявлением функции выглядит чрезмерной тратой места в коде.

Отсюда вопрос - есть ли в MQL5 синтаксис для "короткой записи" функций? Чтобы получилось что-то вроде следующего:

typedef void(*overArrayI)(int &);
int arrayI[3]={1,2,3};
//+------------------------------------------------------------------+
void OnStart()
  {
   ForAll({a -> a++});
   ForAll({a -> a*3});
  }
//+------------------------------------------------------------------+
void ForAll(overArrayI todo)
  {
   for(int i=0;i<3;i++)
      todo(arrayI[i]);
   ArrayPrint(arrayI);
  }
//+------------------------------------------------------------------+


 

2. Немного усложним исходный пример. А именно - пусть в todo2 мы хотим умножать не на заранее известное число, а на переданное как параметр. Тогда нам нужен уже новый тип указателя на функцию. Но тогда и функцию ForAll необходимо сделать под разные типы указателей на todo1 и todo2. Хочется использовать шаблоны функций, а не работает. Собственно вопрос:

Что не так в коде (или указатели с шаблонами не работают? или шаблоны с указателями не работают?:))?

//+------------------------------------------------------------------+
typedef void(*int_void)(int &);
typedef void(*intInt_void) (int&, int);
int arrayI[3]={1,2,3};
//+------------------------------------------------------------------+
void OnStart()
  {
   ForAll(todo1);
   ForAll(todo2);
  }
//+------------------------------------------------------------------+
template <typename T>
void ForAll(T todo)
  {
   for(int i=0;i<3;i++)
      todo(arrayI[i]);
   ArrayPrint(arrayI);
  }
//+------------------------------------------------------------------+
void todo1(int &a)
  {
   Print("a++");
   a++;
  }
//+------------------------------------------------------------------+
void todo2(int &a, int b)
  {
   Print("a*b");
   a*=b;
  }
//+------------------------------------------------------------------+
Получаю "'ForAll' - cannot to apply function template" на обоих вызовах ForAll.
Причина обращения: