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

 
fxsaber #:

Not sure how to keep the functionality (subfield and method) and usability. Perhaps this option would suit your needs.


Application.

That was so quick and now it works just fine, thank you!


To Russia with love❤️! ;-)

 
Once upon a time it was easy to write such a macro in MQL5.
class MqlRatestime
{
public:
  static void f( MqlRates &Value ) { Print(Value.time); }
};

class MqlTicktime
{
public:
  static void f( MqlTick &Value ) { Print(Value.time); }
};

void OnStart()
{  
  MqlRates Rates;
  MqlTick Tick;
  
  MACROS(Rates, time); // MqlRatestime::f(Rates);
  MACROS(Tick, time);  // MqlTicktime::f(Tick);
}


Is this possible in the current version of MQL5? I didn't have the ingenuity to overcome this obstacle:

template declarations are allowed on global, namespace or class scope only
 
fxsaber #:
Once upon a time it was easy to write such a macro in MQL5.


Is this possible in the current version of MQL5? I haven't had the resourcefulness to overcome this obstacle:

I don't understand the task - do you need MqlRatest class (template for it) to be declared inside a macro substitution?
 
mktr8591 #:
I don't understand the task - you need MqlRatest class (template for it) to be declared inside the macro substitution?
It seems to me it's necessary to have different macro substitution for parameters of different type.
Only I don't understand why to do it with macro substitution instead of function overloading.
 
mktr8591 #:
I don't understand the task - you need MqlRatest class (its template) to be declared inside the macro substitution?

No, the classes are already declared. The comments specify what result you want to get. The input to the macro is an object, and the output is a class that contains the name of that object's type.

 
Sergey Gridnev #:
It seems to me it's necessary to have different macro substitution for parameters of different types.
Only I don't understand why this should be done using macro substitution rather than function overloading.

The task was born out of this one.

Forum on trading, automated trading systems and strategy testing

Peculiarities of mql5, tips and tricks

fxsaber, 2022.02.11 15:44

ArraySortStruct_Define(MqlRates, open)
ArraySortStruct_Define(MqlRates, high)
ArraySortStruct_Define(MqlRates, time)

void OnStart()
{
  MqlRates Rates[];
  
  CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, Rates); // Взяли бары
  
  Print("\nБары без сортировки - как получили.");
  ArrayPrint(Rates);
  
  Print("\nСортируем по open-цене.");
  ArraySortStruct(MqlRates, Rates, open);
  ArrayPrint(Rates);

  Print("\nСортируем по high-цене.");
  ArraySortStruct(MqlRates, Rates, high);
  ArrayPrint(Rates);

  Print("\nСортируем по времени.");
  ArraySortStruct(MqlRates, Rates, time);
  ArrayPrint(Rates);
}

I have colored the input parameter, in which I have to specify the type. In this macro I get three input parameters. And I would like two - without type.

 
fxsaber #:

No, the classes are already declared. The comments specify what result you want to get. The input to the macro is an object, and the output is a class that contains the name of that object's type.

I don't know how to solve this problem.

And to ArraySortStruct with two parameters - this is how it works:

#define  ArraySortStruct(ARRAY, FIELD) SortOnField_##FIELD::SORT::Sort(ARRAY)

 ArraySortStruct_Define(SortOnField_, open)
ArraySortStruct_Define(SortOnField_, high)
ArraySortStruct_Define(SortOnField_, time)


void OnStart()
  {

   MqlRates Rates[];

   CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, Rates); // Взяли бары

   Print("\nБары без сортировки - как получили.");
   ArrayPrint(Rates);

   Print("\nСортируем по open-цене.");
   ArraySortStruct(Rates, open);
   ArrayPrint(Rates);

   Print("\nСортируем по high-цене.");
   ArraySortStruct(Rates, high);
   ArrayPrint(Rates);

   Print("\nСортируем по времени.");
   ArraySortStruct(Rates, time);
   ArrayPrint(Rates);
  }
 
mktr8591 #:

And to ArraySortStruct with two parameters - that's how it works:

You're right, thank you! I overdid it on a flat spot. I'll leave your variant for sorting.

// Сортировка массива структур и указателей на объекты по полю.
#define  ArraySortStruct_Define(FIELD)                                            \
namespace SortOnField_##FIELD                                                    \
{                                                                                \
  class SORT                                                                     \
  {                                                                              \
  private:                                                                       \
    template <typename T>                                                        \
    static void Swap( T &Array[], const int i, const int j )                     \
    {                                                                            \
      const T Temp = Array[i];                                                   \
                                                                                 \
      Array[i] = Array[j];                                                       \
      Array[j] = Temp;                                                           \
                                                                                 \
      return;                                                                    \
    }                                                                            \
                                                                                 \
    template <typename T>                                                        \
    static int Partition( T &Array[], const int Start, const int End )           \
    {                                                                            \
      int Marker = Start;                                                        \
                                                                                 \
      for (int i = Start; i <= End; i++)                                         \
        if (Array[i].##FIELD <= Array[End].##FIELD)                              \
        {                                                                        \
          SORT::Swap(Array, i, Marker);                                          \
                                                                                 \
          Marker++;                                                              \
        }                                                                        \
                                                                                 \
       return(Marker - 1);                                                       \
    }                                                                            \
                                                                                 \
    template <typename T>                                                        \
    static void QuickSort( T &Array[], const int Start, const int End )          \
    {                                                                            \
      if (Start < End)                                                           \
      {                                                                          \
        const int Pivot = Partition(Array, Start, End);                          \
                                                                                 \
        SORT::QuickSort(Array, Start, Pivot - 1);                                \
        SORT::QuickSort(Array, Pivot + 1, End);                                  \
      }                                                                          \
                                                                                 \
      return;                                                                    \
    }                                                                            \
                                                                                 \
  public:                                                                        \
    template <typename T>                                                        \
    static void Sort( T &Array[], int Count = WHOLE_ARRAY, const int Start = 0 ) \
    {                                                                            \
      if (Count == WHOLE_ARRAY)                                                  \
        Count = ::ArraySize(Array);                                              \
                                                                                 \
      SORT::QuickSort(Array, Start, Start + Count - 1);                          \
                                                                                 \
      return;                                                                    \
    }                                                                            \
  };                                                                             \
}

#define  ArraySortStruct(ARRAY, FIELD) SortOnField_##FIELD::SORT::Sort(ARRAY)


Application.

ArraySortStruct_Define(open)
ArraySortStruct_Define(high)
ArraySortStruct_Define(time)

void OnStart()
{
  MqlRates Rates[];
  
  CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, Rates); // Взяли бары
  
  Print("\nБары без сортировки - как получили.");
  ArrayPrint(Rates);
  
  Print("\nСортируем по open-цене.");
  ArraySortStruct(Rates, open);
  ArrayPrint(Rates);
  
  Print("\nСортируем по high-цене.");
  ArraySortStruct(Rates, high);
  ArrayPrint(Rates);
  
  Print("\nСортируем по времени.");
  ArraySortStruct(Rates, time);
  ArrayPrint(Rates);
}


ZZY It's a pity, by subfield or method, it doesn't work.

 
This may not be news to anyone, but it's unexpected to me.
If a DLL is used simultaneously in different MT5 programs,
keep in mind that it is loaded once by the first program running that uses it.
That is, the DLL environment is in one common process, no matter how many times you import it.
What's the catch? The global pointers used in the DLL are all in the same shared process space.
And this is very convenient.
 
Roman #:
Maybe this is not news to anyone but it's unexpected for me.
If DLL is used simultaneously in different programs MT5,
, keep in mind that it is loaded once by the first program that uses it.
That is, the state of the DLL is in one common process, no matter how many times you import it.
What's the catch? The global pointers used in the DLL are all in the same shared process space.
And this is very convenient.

This is nothing new, it's the way it's always worked from birth.

Only if the data is larger than __atomic__ should access be wrapped/protected with critical sections (or mutex to terminal std::thread)

Reason: