Fonksiyon Şablonları

Aşırı-yüklenmiş fonksiyonlar genellikle benzer işlemleri gerçekleştirmek için kullanılır. ArraySize(), MQL5 içinde böyle bir fonksiyona örnektir. Herhangi bir dizinin büyüklüğüne dönüş yapar. Gerçekte bu sistem fonksiyonu aşırı yüklenmiştir ve bu aşırı-yükleme uygulamasının tamamı MQL5 yazılım geliştiricilerinden saklanmıştır:

int  ArraySize(
   void&  array[]      // kontrol edilen dizi
   );

Yani MQL5 derleyicisi, fonksiyon çağrıldığında gerekli olanı yapacaktır. Örnek olarak, bunun tamsayı tipli diziler için nasıl yapılabileceğini gösterelim:

int  ArraySize(
   int&  array[]      // int tipi elemanların dizisi
   );

ArraySize() fonksiyonu, tarihsel veri şeklindeki kotasyonlarla çalışabilmek amacıyla, MqlRates tipi bir dizi ile şu şekilde gösterilebilir :

int  ArraySize(
   MqlRates&  array[] // MqlRates tipi verilerle doldurulmuş dizi
   );

Bu şekilde, farklı tipteki verilerle çalışmak için aynı fonksiyonu kullanmak çok uygun bir seçenek haline gelir. Ama bunun için tüm ön çalışma yapılmış olmalıdır. İlgili fonksiyon, doğru şekilde çalışması gereken tüm veri tipleri için aşırı-yüklenmiş olmalıdır.

Uygun bir çözüm vardır. Benzer işlemlerin tüm veri tipleri için çalıştırılması gerekiyorsa fonksiyon şablonları kullanılabilir. Programcı sadece bir fonksiyon şablonu tarifi yazmalıdır. Şablonu tarif ederken fonksiyonun birlikte çalışması gereken kesin veri tipleri yerine, sadece bazı biçimsel parametreleri tanımlamalıyız. Derleyici, tüm tiplerin doğru işlenmesi için, fonksiyon çağrısında kullanılan argümanların tiplerini temel alarak, otomatik olarak çeşitli fonksiyonlar oluşturur.

Fonksiyon şablonu tanımı template anahtar kelimesi ile başlar ve açı parantezler arasındaki biçimsel parametrelerin listesi ile devam eder. Biçimsel parametreler typename anahtar kelimesinden sonra gelir . Biçimsel parametreler sistemde gömülü veya kullanıcı tanımlı tiplerdir. Şu amaçlarla kullanılırlar:

  • fonksiyon argümanlarının tiplerini belirtmek,
  • fonksiyonun dönüş tipini belirtmek,
  • değişkenleri fonksiyon tanımında bildirmek

 

Şablon parametrelerinin sayısı sekizi geçemez. Şablon tanımındaki biçimsel parametreler en az bir kere fonksiyon parametreleri içinde yer almalıdır. Biçimsel parametrelerin isimleri benzersiz olmalıdır.

Aşağıda, sayısal tipli (tamsayı ve reel sayılar) bir dizide en büyük değeri aramak için bir fonksiyon şablonu örneği yer almaktadır:

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

Bu şablon, geçirilmiş dizideki en yüksek değeri bulan ve sonuç olarak bu değere dönüş yapan fonksiyonu tanımlar. Lütfen not edin: MQL5 içindeki ArrayMaximum() fonksiyonu, en yüksek değere değil, bu değeri bulmakta kullanılabilecek indise dönüş yapacaktır. Örnek olarak:

//--- bir dizi oluştur
   double array[];
   int size=50;
   ArrayResize(array,size);
//---  rassal değerler ile doldur
   for(int i=0;i<size;i++)
     {
      array[i]=MathRand();
     }
 
//--- dizideki en yüksek değerin pozisyonunu bul
   int max_position=ArrayMaximum(array);
//--- şimdi en yüksek değerin kendisini al
   double max=array[max_position];
//--- bulunan değeri göster
   Print("Max value = ",max);

Böylece, dizideki değeri bulmak için iki aşamalı bir yol izledik. ArrayMax() fonksiyon şablonuyla, sadece uygun tipte bir diziyi fonksiyona geçirerek, gerekli tipteki sonucu alabiliriz. Yani, son iki satırın yerine

//--- dizideki en yüksek değerin pozisyonunu bul
   int max_position=ArrayMaximum(array);
//--- şimdi dizideki en yüksek değerin kendisini al
   double max=array[max_position];

Artık, dönüş tipinin, fonksiyona geçirilen dizinin tipiyle aynı olduğu tek bir satır kullanabiliriz:

//--- en yüksek değeri bul
   double max=ArrayMax(array);

Bu durumda, ArrayMax() fonksiyonunun dönüş tipi otomatik olarak dizi tipiyle eşleşecektir.

 

Çeşitli veri tipleriyle genel amaçlı çalışma yöntemleri oluşturmak ve argüman tipini 'string' olarak almak için typename anahtar sözcüğünü kullanın. Veri tipini dizgi olarak döndüren özel bir fonksiyon örneğini göz önüne getirelim:

#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));
//--- 
  }
//+------------------------------------------------------------------+
//| Tip, bir satır şeklinde döndürülür                               |
//+------------------------------------------------------------------+
template<typename T>
string GetTypeName(const T &t)
  {
//--- tipi bir satır şeklinde döndür
   return(typename(T));
//---
  }

 

Fonksiyon şablonları sınıf yöntemleri için de kullanılabilirler, örneğin:

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

Fonksiyon şablonları, export, virtual ve #import anahtar sözcükleri ile bildirilmemelidir.

Şablon fonksiyonunun aşırı yüklenmesi

Bazen şablon fonksiyonların da aşırı yüklenmesi gerekebilir. Örneğin tip dönüştürme kullanarak ikinci parametrenin değerini birinciye atayan bir şablon fonksiyonumuz olabilir. MQL5, string ve bool tipleri arasında tip dönüşümüne izin vermez.. Bunu kendimiz yapabiliriz – şimdi bir şablon fonksiyonunu aşırı yükleyelim. Örneğin:

//+------------------------------------------------------------------+
//| Şablon fonksiyon                                                 |
//+------------------------------------------------------------------+
template<typename T1,typename T2>
string Assign(T1 &var1,T2 var2)
  {
   var1=(T1)var2;
   return(__FUNCSIG__);
  }
//+------------------------------------------------------------------+
//| bool+string için özel aşırı yükleme                              |
//+------------------------------------------------------------------+
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"));
  }

Kod çalıştırıldığında, sonuç olarak Assign() şablonunun int+string çifti için kullanıldığını görebiliriz, aşırı yüklenmiş versiyon ise ikinci çağrı sırasında bool+string çifti için zaten kullanmış durumda.

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

Ayrıca bakınız

Aşırı Yükleme