Templates di Funzioni

Funzioni overloadate vengono comunemente utilizzati per eseguire operazioni simili su vari tipi di dati. ArraySize() è un semplice esempio di tale funzione in MQL5. Restituisce la grandezza di qualsiasi tipo di array. In realtà, questa funzione di sistema è overloadata e l'intera implementazione di un tale sovraccarico è nascosto agli sviluppatori di applicazioni MQL5:

int  ArraySize(
   void&  array[]      // array verificato
   );

Ciò significa che il compilatore del linguaggio MQL5 inserisce implementazioni necessarie per ogni chiamata di questa funzione. Ad esempio, è così che si può fare per gli array di tipo double:

int  ArraySize(
   int&  array[]      // array con elementi di tipo int
   );

La funzione Arraysize() può essere visualizzata nel modo seguente per il tipo di array MqlRates per l'utilizzo di quotazioni in formato dati storici:

int  ArraySize(
   MqlRates&  array[] // array riempito con valori di tipo MqlRates
   );

Pertanto, è molto conveniente utilizzare la stessa funzione per lavorare con differenti tipi. Ad ogni modo, dev' essere effettuato tutto il lavoro preliminare - la funzione necessaria deve essere overloadata per tutti i tipi di dati con cui dovrebbe funzionare correttamente.

C'è una soluzione conveniente. Se operazioni simili devono essere eseguite per ogni tipo di dati, è possibile utilizzare i modelli di funzione. In questo caso, un programmatore ha bisogno di scrivere solo una descrizione del template funzione. Quando si descrive il template in modo tale, dovremmo specificare solo qualche parametro formale invece di un tipo definito di dati con cui la funzione dovrebbe lavorare. Il compilatore genera automaticamente varie funzioni per la corretta gestione di ogni tipo in base ai tipi di argomenti utilizzati quando si chiama la funzione.

La definizione del template di funzione inizia con la parola chiave template seguita dalla lista dei parametri formali tra parentesi angolari. Ogni parametro formale è preceduto dalla parola chiave typename. I tipi di parametri formali sono di tipo built-in o definiti-dall'utente. Essi sono utilizzati:

  • per specificare i tipi di argomenti della funzione,
  • per specificare il tipo di valore di ritorno della funzione,
  • per dichiarare le variabili all'interno della definizione di funzione

 

Il numero di parametri del modello non può essere superiore ad otto. Ogni parametro formale nella definizione del modello dovrebbe apparire nella lista dei parametri della funzione almeno una volta. Ogni nome del parametro formale deve essere univoco.

Di seguito è riportato un esempio di un modello di funzione per ricercare il valore più alto nell' array di qualsiasi tipo numerico (numeri interi e reali):

template<typename T>
T ArrayMax(T &arr[])
  {
   uint size=ArraySize(arr);
   if(size==0) return(0);          
   
   T max=arr[0];
   for(uint n=1;n<size;n++)
      if(max<arr[n]) max=arr[n];
//---
   return(max);
  }

Questo template definisce la funzione che rileva il valore massimo nell'array passato e restituisce questo valore come risultato. Tenete a mente che la funzione ArrayMaximum() costruita in MQL5 restituisce solo l'indice di più alto valore che può essere utilizzato per trovare il valore stesso. Ad esempio:

//--- crea un array
   double array[];
   int size=50;
   ArrayResize(array,size);
//---  riempie con valori casuali
   for(int i=0;i<size;i++)
     {
      array[i]=MathRand();
     }
 
//--- trova la posizione del valore più elevato nell'array
   int max_position=ArrayMaximum(array);
//--- ora ottiene il valore stesso più elevato, nell'array
   double max=array[max_position];
//--- mostra il valore trovato
   Print("Max value = ",max);

Così, abbiamo effettuato due passaggi per ottenere il più alto valore nell'array. Con il template di funzione ArrayMax(), si può ottenere il risultato del tipo necessario semplicemente passando l'array di un tipo appropriato in questa funzione. Significa che invece delle ultime due righe

//--- trova la posizione del valore più elevato nell'array
   int max_position=ArrayMaximum(array);
//--- ora riceve il valore stesso più elevato, nell'array
   double max=array[max_position];

ora è possibile utilizzare una sola riga, in cui il risultato restituito ha lo stesso tipo dell'array passato nella funzione:

//--- trova il valore più alto
   double max=ArrayMax(array);

In questo caso, il tipo di risultato restituito dalla funzione ArrayMax() funzione abbina automaticamente il tipo di matrice.

 

Utilizzare la parola chiave typename per ottenere il tipo di argomento come stringa al fine di creare i metodi di uso generale di lavoro con diversi tipi di dati. Consideriamo un esempio specifico della funzione che restituisce tipo di dati come una stringa:

#include <Trade\Trade.mqh>
//+--------------------------------------------------------------------------------+
//|                                                                                |
//+--------------------------------------------------------------------------------+
voidOnStart()
  {
//--- 
   CTrade trade;   
   double d_value=M_PI;
   int i_value=INT_MAX;
   Print("d_value: type=",GetTypeName(d_value), ",   value=", d_value);
   Print("i_value: type=",GetTypeName(i_value), ",   value=", i_value);
   Print("trade: type=",GetTypeName(trade));
//--- 
  }
//+--------------------------------------------------------------------------------+
//| Il tipo viene restituito come una linea                                        |
//+--------------------------------------------------------------------------------+
template<typename T>
string GetTypeName(const T &t)
  {
//--- restituisce il tipo come una linea
   return(typename(T));
//---
  }

 

Templates di funzioni possono anche essere utilizzati per metodi della classe, per esempio:

class CFile
  {
   ...
public:
   ...
   template<typename T>
   uint WriteStruct(T &data);
  };
 
template<typename T>
uint CFile::WriteStruct(T &data)
  {
   ...
   return(FileWriteStruct(m_handle,data));
  }

Templates di funzioni non devono essere dichiarati con le parole chiave export, virtual e #import.

Overload della funzione template

Un sovraccarico di funzione template può essere necessario a volte. Per esempio, abbiamo una funzione template che scrive il valore del secondo parametro nel primo utilizzando typecasting. MQL5 non consente typecasting string a bool. Possiamo farlo noi stessi - creiamo un sovraccarico di una funzione template. Per esempio:

//+------------------------------------------------------------------+
//| Funzione Template                                                |
//+------------------------------------------------------------------+
template<typename T1,typename T2>
string Assign(T1 &var1,T2 var2)
  {
   var1=(T1)var2;
   return(__FUNCSIG__);
  }
//+------------------------------------------------------------------+
//| Speciale overload per bool+string                                |
//+------------------------------------------------------------------+
string Assign(bool &var1,string var2)
  {
   var1=(StringCompare(var2,"true",false) || StringToInteger(var2)!=0);
   return(__FUNCSIG__);
  }
//+------------------------------------------------------------------+
//| Funzione di start del programma Script                           |
//+------------------------------------------------------------------+
void OnStart()
  {
   int i;
   bool b;
   Print(Assign(i,"test"));
   Print(Assign(b,"test"));
  }

Come risultato dell'esecuzione del codice, possiamo vedere che la funzione template Assign() è stata utilizzata per la coppia int+string, mentre la versione overload è già stata utilizzata per la coppia string+bool durante la seconda chiamata.

string Assign<int,string>(int&,string)
string Assign(bool&,string)

Guarda anche

Overload