Особенности языка mql5, тонкости и приёмы работы - страница 138

 
fxsaber:
// Некоторые возможности структур, которых нет у классов.

хм, интересно, очень с const полями понравилась идея, const будут инициализированы всего один раз

 
Igor Makanu:

хм, интересно, очень с const полями понравилась идея, const будут инициализированы всего один раз

можно теперь так сделать нормализацию лота:

В классах тоже можно константные члены объявлять.

 
Andrey Barinov:

В классах тоже можно константные члены объявлять.

ну да, тут в общем я толком не использую все модификаторы, поэтому это и вызвало мое восхищение, проверил, теперь обфусцировал код, хотя хотел просто записать компактно )))

#property strict
//+------------------------------------------------------------------+
class NL
  {
#ifndef SID #define SID(v) SymbolInfoDouble(_Symbol,v)
private: const class sl
     {
   public:double     s,b,l;int d;sl():s(SID(SYMBOL_VOLUME_STEP)),b(SID(SYMBOL_VOLUME_MAX)),l(SID(SYMBOL_VOLUME_MIN)){;long i=10000000,k=long(s/0.0000001);d=0;while(d<7 && k%i>0){i/=10;d++;}}#endif
     }
   param; public:   double Lot(double value){return(NormalizeDouble(fmax(fmin(param.s*round(value/param.s),param.b),param.l),param.d));}
  }
Normalize;
//+------------------------------------------------------------------+
void OnStart()
  {
   double l = 0.0;
   for(int i=0;i<10;i++)
     {
      l+=0.005;
      Print(Normalize.Lot(l));
     }
  }
//+------------------------------------------------------------------+
ЗЫ: фолдинга в МЕ жесть как не хватает! - напрягает колесиком мыши тудымсюдым крутить  (((
 

Моя реализация конструкции for each  средствами MQL.

Пока работает только для массивов:  1) штатные mql-массивы;  2) пользовательские классы массивов, у которых должен быть определён оператор [](int), а также перегружена глобальная функция ArraySize.

Синтаксис:

 foreach(element_var, array)  { ... }

Массив может быть задан как переменной, так и выражением - именно из-за этого и пришлось городить огород )   Выражение выполняется однократно, сохраняя указатель на массив, и затем производится доступ по этому указателю.


#define TEMPL(T) template<typename T>


enum E_TRUE  { __TRUE=1 };
enum E_FALSE { __FALSE=0 };

TEMPL(T) E_TRUE  __IsMqlArray(T&[], int) { return true; }
TEMPL(T) E_FALSE __IsMqlArray(T&, int)   { return false; }
TEMPL(T) E_FALSE __IsMqlArray(T, uint)   { return false; }

#define IS_MQL_ARRAY(var)  ( typename(__IsMqlArray(var, 0))==typename(E_TRUE) )


static
class __CForeachHelper
{
 public:
  TEMPL(T)
  class __CDummyArr { public: T data[]; };
  TEMPL(T)
  struct __TValue { public:  T data;  __TValue(T value) { data= value; } };
   
  TEMPL(T) T*    Ptr(T* a) { return a; }
  TEMPL(T) T*    Ptr(T& a) { return &a; }
  TEMPL(T) __CDummyArr<T>* Ptr(const T&[])  { return NULL; }
  
  TEMPL(T) __TValue<T>     Obj(const void* p, T)               { return (T)p; }
  TEMPL(T) __CDummyArr<T>* Obj(const void* p, __CDummyArr<T>*) { return (__CDummyArr<T>*)p; }
}
__foreachhelper;


#define __ARR_ITEM(ptr, array, i)  (IS_MQL_ARRAY(array) ? array[i] : __foreachhelper.Obj(ptr,  0 ?__foreachhelper.Ptr(array) : NULL).data[i])

#define __ARR_SIZE(ptr, array) (IS_MQL_ARRAY(array) ? ArraySize(array) : ArraySize(__foreachhelper.Obj(ptr,  0 ?__foreachhelper.Ptr(array) : NULL).data))


#define CONCAT(a, b) a##b

#define CONCAT2(a, b) CONCAT(a, b)


#define __FORVAR(var) CONCAT2(__for##var, __LINE__)


#define foreach(element, array) \
  if (0) { class __CForeachArrCheck \ // Проверка наличия конструктора у элемента mql-массива
           { public: TEMPL(T) void f(T&){}  TEMPL(T) void f(T*){}  TEMPL(T) void f(T*const&[]){}  TEMPL(T) void f(T const&[]) { T arr[1]; } \           
           } _fcheck;  _fcheck.f(array); \
         } \
  else \
  for (int __FORVAR(state)=1;  __FORVAR(state)==1; ) \
   for (const void* __FORVAR(ptr)=__foreachhelper.Ptr(array);  __FORVAR(state)==1; ) \
     for(int __FORVAR(i)=0, __FORVAR(count)=__ARR_SIZE(__FORVAR(ptr), array);  __FORVAR(state)--==1 && __FORVAR(i)<__FORVAR(count);  __FORVAR(i)++) \
       for (element=__ARR_ITEM(__FORVAR(ptr), array, __FORVAR(i));  __FORVAR(state)==0;  __FORVAR(state)=1)


Примеры использования:

template<typename T>
class CArr
{ 
 public: 
  T data[];
  T    operator[](int i)   const { return data[i]; }
  void operator=(T const &arr[]) { int size=ArraySize(arr);  ArrayResize(data, size);  for (int i=0; i<size; i++) data[i]=arr[i]; }
};


template<typename T>
int ArraySize(const CArr<T> &arr) { return ArraySize(arr.data); }


class A { public: double value;  A(double val=0) { value=val; } };


CArr<int>* GetArr() { Print("Get Array");  static int arr[]={10,20,30};  static CArr<int> Arr= arr;  return &Arr; }


void OnStart()
{
  Print("Test 1");
  double arr[]= { 10, 20, 30 };
            
  foreach(double val, arr) Print(val);
       
  Print("Test 2");
  CArr<double> arr2 = arr;
       
  foreach(double val, arr2) Print(val);

         
  Print("Test 3");
  A _a(10), _b(20), _c(30);
  A* arr3[3];
  arr3[0]=&_a;  arr3[1]=&_b;  arr3[2]=&_c;
       
  foreach(A* a, arr3) Print(a.value);

  Print("Test 4");
  CArr<A*> arr4 = arr3;

  foreach(A* a, arr4) Print(a.value);


  Print("Test 5");

  foreach(int a, GetArr()) Print(a);
}
 
Alexey Navoykov:

Примеры использования:

Немного переписал

  //void operator=(T const &arr[]) { int size=ArraySize(arr);  ArrayResize(data, size);  for (int i=0; i<size; i++) data[i]=arr[i]; }
  void operator=(T const &arr[]) { ArrayResize(data, ArrayCopy(data, arr)); }
 
Alexey Navoykov:

Моя реализация конструкции for each  средствами MQL.

Пока работает только для массивов:  1) штатные mql-массивы;  2) пользовательские классы массивов, у которых должен быть определён оператор [](int), а также перегружена глобальная функция ArraySize.

Классно вышло! Возможно ли сделать такой вариант?

void OnStart()
{
  MqlTick Ticks[3];
  
  for (int i = 0; i < ArraySize(Ticks); i++)
    Ticks[i].bid = i + 1;

  foreach(MqlTick Tick, Ticks) Print(Tick.bid); // OK
    
  foreach(MqlTick Tick[1], Ticks) ArrayPrint(Tick); // 'Tick' - invalid array access   
}
 
fxsaber:

Классно вышло! Возможно ли сделать такой вариант?

Ну инициализация массива переменными не поддерживается в MQL.  Можно сделать присваивание элементу массива:

foreach(Ticks[0], Ticks) ArrayPrint(Ticks[0].bid);

 
Alexey Navoykov:
Ну инициализация массива переменными не поддерживается в MQL.  Можно сделать присваивание элементу массива:

В реализации не разобрался, но так делать не вижу смысла.


Такой вариант не работает

void f( const int &Array[] )
{
  foreach(int val, Array) Print(val);
}
 
fxsaber:

Такой вариант не работает

Да, действительно.   Начав разбираться, я открыл для себя интересную особенность. При передаче в шаблон аргумента константного типа (например const int)  внутри шаблона он воспринимается просто как: T = int,  однако и константность тоже каким-то образом учитывается, что сбивает с толку:
template<typename T>
class B { };

template<typename T>
void f(T & a)
{ 
  B<const T> b;     // OK. Значит T==int
  const T arr[]={}; // Тоже всё ОК.
  T arr2[];         // 'arr2' - 'const' variable must be initialized.  wtf?
} 

void OnStart()
{
  const int a=0;
  f(a);
}

Сначала подумал, это особенность MQL,  но и в C++ так же.

 
Alexey Navoykov:

Сначала подумал, это особенность MQL,  но и в C++ так же.

потому что тип const int. просто в шаблоне к нему все равно без проблем можно пришпилить const спереди

но если в c++ можно нехитрыми манипуляциями убрать const у типа, то в mql этого сделать нельзя

Причина обращения: