Características da linguagem mql5, subtilezas e técnicas - página 138

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

hm, interessante, gostou muito da ideia com const fields, const só será rubricada uma vez

 
Igor Makanu:

hm, interessante, gosto da ideia com campos const, const será inicializada apenas uma vez

pode agora fazer a normalização de lotes desta forma:

Também se pode declarar membros constantes nas aulas.

 
Andrey Barinov:

Também pode declarar membros constantes nas aulas.

Bem, sim, eu não uso todos os modificadores adequadamente aqui, por isso causou a minha admiração, eu verifiquei-o, agora ofusquei o código, embora quisesse apenas escrevê-lo de forma compacta ))))

#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: a dobragem em ME é realmente inexistente! - é cansativo rodar a roda do rato aqui e ali (((
 

A minha implementação de construção para cada um pela MQL.

Até agora, só funciona para arrays: 1) mql-arrays regulares; 2) classes de array personalizadas, que devem ter [](int) operador definido efunção ArraySize global sobrecarregada.

Sintaxe:

 foreach(element_var, array)  { ... }

Uma matriz pode ser definida como uma variável ou uma expressão - é por isso que tivemos de construir o jardim). A expressão é executada uma vez, armazenando um ponteiro para a matriz, e depois acedendo ao ponteiro.


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


Exemplos de utilização:

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:

Exemplos de utilização:

Um pouco reescrito

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

A minha implementação de construção para cada um pela MQL.

Até agora, funciona apenas para arrays: 1) mql-arrays regulares; 2) classes de arrays personalizadas, que devem ter [](int) operador definido e função ArraySize global sobrecarregada.

Isso é fixe! É possível fazer uma tal variante?

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:

Isso é fixe! É possível fazer uma versão disto?

Bem, inicializar um array com variáveis não é suportado no MQL. Pode fazer uma atribuição a um elemento do array:

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

 
Alexey Navoykov:
Bem, inicializar um array com variáveis não é suportado no MQL. Pode fazer uma atribuição a um elemento do array:

Ainda não descobri a implementação, mas não vejo a utilidade de o fazer dessa forma.


Isto não funciona

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

Esta variante não funciona

Sim, é. Quando comecei a investigar o assunto, descobri uma peculiaridade interessante. Quando um argumento de tipo constante(const int, por exemplo) é passado para um modelo, é tomado simplesmente como: T = int, mas a constância é de alguma forma também tida em conta, o que é confuso:
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);
}

No início pensei que era uma característica da MQL, mas é a mesma coisa em C++.

 
Alexey Navoykov:

No início pensei que era uma característica da MQL, mas é o mesmo em C++ também.

porque o tipo é const. int. é que no modelo ainda se pode anexar const. à frente sem problemas

mas se em c++ pode remover constantes de um tipo através de algumas manipulações simples, não o pode fazer em mql.