Templates de fonction

Les fonctions surchargées sont communément utilisées pour effectuer des opérations similaires sur différents types de données. ArraySize() est un exemple simple de ce genre de fonction en MQL5. Elle retourne la taille de n'importe quel type de tableau. En fait, cette fonction système est surchargée et l'implémentation entière de ce genre de surcharge est masquée pour les développeurs d'applications MQL5 :

int  ArraySize(
   void&  array[]      // tableau vérifié
   );

Cela signifie que le compilateur du langage MQL5 insère l'implémentation nécessaire pour chaque appel à cette fonction. Par exemple, voici comment cela peut être fait pour les tableaux d'entiers :

int  ArraySize(
   int&  array[]      // tableau avec des éléments de type int
   );

La fonction ArraySize() peut être affichée de la façon suivante pour le tableau de types MqlRates pour utiliser les cotations au format des données historiques :

int  ArraySize(
   MqlRates&  array[] // tableau rempli avec des valeurs de type MqlRates
   );

Il est donc très pratique d'utiliser la même fonction pour travailler avec des types différents. Cependant, tout le travail préliminaire doit être effectué — la fonction nécessaire doit être surchargée pour tous les types de données pour lesquels elle sera appelée.

Il y a une solution pratique. Si des opérations similaires doivent être exécutées pour chaque type de données, il est possible d'utiliser des templates de fonctions. Dans ce cas, le programmeur doit n'écrire qu'une seule description pour le template de la fonction. Lors de la description du template de cette façon, nous ne devons spécifier que certains paramètres formels au lieu des type de données définis avec lesquels la fonction doit travailler. Le compilateur génèrera automatiquement les différentes fonction pour gérer chaque type nécessaire sur la base des types des arguments utilisés lors des appels à la fonction.

La définition d'un template de fonction commence avec le mot-clé template suivi de la liste des paramètres formels entre chevrons. Chaque paramètre formel est précédé du mot-clé typename. Les types des paramètres formels sont des types intégrés ou définis par l'utilisateur. Ils sont utilisés :

  • pour spécifier les types des arguments de la fonction,
  • pour spécifier le type de la valeur de retour de la fonction,
  • pour déclarer les variables dans la définition de la fonction

 

Le nombre de paramètres template ne peut pas être supérieur à 8. Chaque paramètre formel dans la définition du template devrait apparaître dans la liste des paramètres de la fonction au moins une fois. Chaque nom de paramètre formel doit être unique.

Ci-dessous se trouve un exemple de template de fonction pour chercher la plus grande valeur dans un tableau de types numériques (nombres entiers et réels) :

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);
  }

Ce template définit la fonction qui chercher la plus grande valeur dans le tableau passé et retourne cette valeur comme résultat. Gardez à l'esprit que la fonction ArrayMaximum() intégrée en MQL5 ne retourne que l'indice de la plus grande valeur qui peut être utilisée pour trouver la valeur elle-même. Par exemple :

//--- crée un tableau
   double array[];
   int size=50;
   ArrayResize(array,size);
//---  remplit avec des valeurs aléatoires
   for(int i=0;i<size;i++)
     {
      array[i]=MathRand();
     }
 
//--- trouve la position de la plus grande valeur du tableau
   int max_position=ArrayMaximum(array);
//--- maintenant, récupère la plus grande valeur elle-même du tableau
   double max=array[max_position];
//--- affiche la valeur trouvée
   Print("Valeur max = ",max);

Nous avons donc effectué deux étapes pour trouver la plus grande valeur dans le tableau. Avec le template de fonction ArrayMax(), nous pouvons trouver le résultat du type désiré en passant juste le tableau du type désiré à cette fonction. Cela signifie qu'au lieu des 2 dernière lignes

//--- trouve la position de la plus grande valeur du tableau
   int max_position=ArrayMaximum(array);
//--- maintenant, récupère la plus grande valeur elle-même du tableau
   double max=array[max_position];

nous pouvons maintenant n'utiliser qu'une seule ligne, dans laquelle le résultat retourné a le même type que le tableau passé à la fonction :

//--- trouve la plus grande valeur
   double max=ArrayMax(array);

Dans ce cas, le type du résultat retourné par la fonction ArrayMax() correspondra automatiquement au type du tableau.

 

Utilisez le mot-clé typename pour récupérer le type de l'argument sous la forme d'une chaîne de caractères pour créer des méthodes générales pour pouvoir travailler avec différents types de données. Considérons un exemple spécifique de la fonction qui retourne un type de données sous la forme d'une chaîne de caractères :

#include <Trade\Trade.mqh>
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnStart()
  {
//--- 
   CTrade trade;   
   double d_value=M_PI;
   int i_value=INT_MAX;
   Print("d_value: type=",GetTypeName(d_value), ",   valueur=", d_value);
   Print("i_value: type=",GetTypeName(i_value), ",   valeur=", i_value);
   Print("trade: type=",GetTypeName(trade));
//--- 
  }
//+------------------------------------------------------------------+
//| Le type est retourné sous forme de texte                         |
//+------------------------------------------------------------------+
template<typename T>
string GetTypeName(const T &t)
  {
//--- retourne le type sous forme de texte
   return(typename(T));
//---
  }

 

Les templates de fonction peuvent également être utilisés pour les méthodes de classe, par exemple :

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

Les templates de fonction ne doivent pas être déclarés avec les mots-clés export, virtual et #import.

Surcharge de template de fonction

La surcharge d'une fonction templatée peut être nécessaire parfois. Par exemple, nous avons une fonctions templatée qui écrit la valeur du deuxième paramètre dans le premier en utilisant une conversion de type. MQL5 ne permet pas la conversion du type string en bool. Nous pouvons le faire nous-mêmes — créons la surcharge d'une fonction templatée. Par exemple :

//+------------------------------------------------------------------+
//| Template de fonction                                             |
//+------------------------------------------------------------------+
template<typename T1,typename T2>
string Assign(T1 &var1,T2 var2)
  {
   var1=(T1)var2;
   return(__FUNCSIG__);
  }
//+------------------------------------------------------------------+
//| Surcharge spéciale pour bool+string                              |
//+------------------------------------------------------------------+
string Assign(bool &var1,string var2)
  {
   var1=(StringCompare(var2,"true",false) || StringToInteger(var2)!=0);
   return(__FUNCSIG__);
  }
//+------------------------------------------------------------------+
//| Fonction de lancement du programme                               |
//+------------------------------------------------------------------+
void OnStart()
  {
   int i;
   bool b;
   Print(Assign(i,"test"));
   Print(Assign(b,"test"));
  }

Nous pouvons voir comme résultat de l'exécution du code que la fonction templatée Assign() a été utilisée pour la paire int+string, tandis que la version surchargée a déjà été utilisée pour la paire bool+string pendant le deuxième appel.

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

Voir aussi

Surcharge