Features of the mql5 language, subtleties and tricks - page 138

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

hm, interesting, really liked the idea with const fields, const will only be initialised once

 
Igor Makanu:

hm, interesting, I like the idea with const fields, const will be initialized only once

you can now do lot normalization in this way:

You can declare constant members in classes too.

 
Andrey Barinov:

You can also declare constant members in classes.

Well, yes, I don't use all modifiers properly here, that's why it caused my admiration, I checked it, now I obfuscated the code, though I wanted just to write it compactly ))))

#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));
     }
  }
//+------------------------------------------------------------------+
ZS: the folding in ME is really lacking! - it's tiring to roll the mouse wheel here and there (((
 

My implementation of construct for each by MQL.

So far, it only works for arrays: 1) regular mql-arrays; 2) custom array classes, which should have [](int) operator defined and globalArraySize function overloaded.

Syntax:

 foreach(element_var, array)  { ... }

An array can be defined as either a variable or an expression - that's why we had to build the garden.) The expression is executed once, storing a pointer to the array, and then accessing the pointer.


#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)


Usage examples:

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:

Examples of use:

A little rewritten

  //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:

My implementation of construct for each by MQL.

So far, it works only for arrays: 1) regular mql-arrays; 2) custom array classes, which should have [](int) operator defined and global ArraySize function overloaded.

That's cool! Is it possible to make such a variant?

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:

That's cool! Is it possible to do a version of this?

Well, initializing an array with variables is not supported in MQL. You can make an assignment to an array element:

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

 
Alexey Navoykov:
Well, initializing an array with variables is not supported in MQL. You can do an assignment to an array element:

I haven't figured out the implementation, but I don't see the point in doing it that way.


This does not work

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

This variant doesn't work

Yes, it is. When I started to look into it, I discovered an interesting peculiarity. When an argument of a constant type (const int, for example) is passed to a template, it is taken simply as: T = int, but the constancy is somehow taken into account too, which is confusing:
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);
}

At first I thought it was a feature of MQL, but it's the same in C++.

 
Alexey Navoykov:

At first I thought it was a feature of MQL, but it's the same in C++ too.

because the type is const int. it is just that in the template you can still attach const to the front without any problems

but if in c++ you can remove const from a type by some simple manipulations, you can't do it in mql.