Funktionstemplates

Überladene Funktionen werden häufig verwendet, um ähnliche Operationen auf verschiedene Datentypen durchzuführen. Ein einfaches Beispiel für eine solche Funktion im MQL5 ist ArraySize(), die die Größe des Arrays jeder Art zurück gibt. In der Tat ist dieses System Funktion überladen, und die ganze Umsetzung dieses Überladen wird von der MQL5 Software-Entwickler versteckt:

int  ArraySize(
   void&  array[]      // Array zu prüfen
   );

MQL5 Compiler MQL5 ersetzt eine rechte Umsetzung für jeden Aufruf dieser Funktion. Zum Beispiel für Arrays von Typ integer:

int  ArraySize(
   int&  array[]      // Array mit Elementen vom Typ int
   );

Und für einem Array vom Typ MqlRates für Arbeit mit Preise im Format von historischen Daten kann Funktion ArraySize() wie folgt dargestellt werden:

int  ArraySize(
   MqlRates&  array[] // Array mit Elementen vom Typ MqlRates
   );

Somit ist es sehr praktisch, die gleiche Funktion für verschiedenen Typen zu nutzen, aber Sie müssen Vorarbeiten ausführen - nämlich Überladen der Funktion für alle Datentypen, mit denen sie arbeitet.

Es gibt eine bequeme Lösung - wenn für jeden Datentyp identische Operationen durchgeführt werden sollte, gibt es eine kompakte und praktische Lösung, Funktionsschablonen zu verwenden. In diesem Fall muss der Programmierer nur eine Beschreibung der Funktionsschablone zu schreiben. Für diese Beschreibung der Schablone, müssen Sie nicht einen spezifischen Datentyp, mit dem die Funktion arbeiten soll, als Parameter eingeben, sondern einen formalen Parameter. Basierend auf der Typen der verwendeten Argumente beim Aufruf der Funktion, wird der Compiler automatisch verschiedene Funktionen für die geeignete Behandlung für jeden Typ generieren.

Die Definition einer Funktionsschablone beginnt mit dem Schlüsselwort template wonach in spitzen Klammern ist eine Liste der formalen Parameter. Jeder formale Parameter wird durch das Schlüsselwort typename vorangestellt. Die formalen Parameter-Typen sind eingebaute Typen oder benutzerdefinierte Typen. Sie werden verwendet:

  • um die Type der Argumente der Funktion einzugeben
  • um den Typ des Rückgabewerts der Funktion einzugeben
  • um Variablen innerhalb des Körpers der Beschreibung der Funktion zu erklären

 

Die Anzahl der Parameter in einer Schablone kann nicht mehr als acht sein. Jeder formale Parameter in der Schablone-Definition sollte mindestens einmal in der Funktion Parameter-Liste erscheinen. Jeder Name vom formalen Parameter muss eindeutig sein.

Hier ist ein Beispiel für ein Funktionsschablone für die Suche nach den maximalen Wert in einem Array von beliebigen numerischen Typs (integer und reelle Zahlen):

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

Dieses Beispiel beschreibt eine Funktion, die den größten Wert in dem übergebenen Array findet, um es als Ergebnis zurück zu geben. Daran erinnern, dass die eingebaute MQL5 Funktion ArrayMaximum() gibt nur der Index des gefundenen Maximalwert zurück, mit dem der Benutzer kann in der Zukunft den Wert selbst bekommen. Zum Beispiel:

//--- Erstellen wir ein Array
   double array[];
   int size=50;
   ArrayResize(array,size);
//---  Füllen es mit zufälligen Werten
   for(int i=0;i<size;i++)
     {
      array[i]=MathRand();
     }
 
//--- Finden wir die Position der maximalen Element im Array
   int max_position=ArrayMaximum(array);
//--- Bekommen wir das Maximalwert im Array
   double max=array[max_position];
//--- Ausgabe des gefundenen Wertes
   Print("Max value = ",max);

So brauchen wir zwei Schritte, um den maximalen Wert in dem Array zu erhalten. Mit Hilfe der Funktionsschablone ArrayMax() kann man das Ergebnis vom gewünschten Typ erhalten, wenn man ein Array des entsprechenden Typs in sie übergibt. Das heißt, anstelle der zwei letzten Zeilen

//--- Finden wir die Position der maximalen Element im Array
   int max_position=ArrayMaximum(array);
//--- Bekommen wir das Maximalwert im Array
   double max=array[max_position];

Jetzt können wir nur eine einzige Zeile, die ein Ergebnis des gleichen Typs wie der übergebenen Array zurückgibt, benutzen:

//--- Finden wir den maximalen Wert
   double max=ArrayMax(array);

Der Typ des Ergebnisses, der durch ArrayMax() zurückgegeben wird, wird automatisch mit dem Typ des Arrays gleich sein.

 

Um mit verschiedenen Typen von Daten zu arbeiten, müssen Sie das Schlüsselwort typename verwenden, um den Typ des Arguments als Zeichen zu erhalten. Wir zeigen dies am Beispiel einer Funktion, die einen Datentyp als String zurückgibt:

#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), ",   value=", d_value);
   Print("i_value: type=",GetTypeName(i_value), ",   value=", i_value);
   Print("trade: type=",GetTypeName(trade));
//--- 
  }
//+------------------------------------------------------------------+
//| Gibt den Typ als String zurück                                   |
//+------------------------------------------------------------------+
template<typename T>
string GetTypeName(const T &t)
  {
//--- den Typ als String zurückgeben
   return(typename(T));
//---
  }

 

Funktionsschablonen können auch für Klassenmethode verwendet werden, zum Beispiel:

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

Funktionsschablonen können nicht mit den Schlüsselwörtern export, virtual und #import deklariert werden.

Überladen von Funktionstemplates

In einigen Fällen müssen Funktionen überladen werden. Wir haben zum Beispiel ein Funktionstemplate, das den Wert des zweiten Parameters in den ersten Parameter mithilfe der expliziten Typenumwandlungschreibt. In der MQL5-Programmiersprache ist es verboten, den string Typ in den bool Typ umzuwandeln, wir können das selbst tun - dafür erstellen wir die Überladung des Funktiostempaltes. Zum Beispiel:

//+------------------------------------------------------------------+
//| Funktionsvorlage                                                |
//+------------------------------------------------------------------+
template<typename T1,typename T2>
string Assign(T1 &var1,T2 var2)
  {
   var1=(T1)var2;
   return(__FUNCSIG__);
  }
//+------------------------------------------------------------------+
//| Spezielle Überladung für den Fall bool+string                    |
//+------------------------------------------------------------------+
string Assign(bool &var1,string var2)
  {
   var1=(StringCompare(var2,"true",false) || StringToInteger(var2)!=0);
   return(__FUNCSIG__);
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   int i;
   bool b;
   Print(Assign(i,"test"));
   Print(Assign(b,"test"));
  }

Wenn der Code ausgeführt wird, können wir sehen, dass für das Paar int+string das Funktionstemplate Assign() verwendet wurde und bei dem zweiten Aufruf für das Paar bool+string die überladene Version verwendet.

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

Siehe auch

Überladung