Şablon avantajları

Fonksiyon şablonları çeşitli veri tiplerinde benzer işlemler yapmak istediğinizde kullanılır (bir dizideki maksimum değerli elmanı bulmak gibi).  Şablonların avantajı, her farklı tip için ayrı aşırı yükleme yapmanızı gerektirmemesidir. Her farklı veri tipi için aşırı yükleme yapmak yerine

double ArrayMax(double array[])
  {
  ... 
  }
int ArrayMax(int array[])
  {
  ... 
  }
uint ArrayMax(uint array[])
  {
  ... 
  }
long ArrayMax(long array[])
  {
  ... 
  }
datetime ArrayMax(datetime array[])
  {
  ... 
  }

sadece bir şablon fonsiyonu yazmamız yeterli

template<typename T> 
T ArrayMax(T array[])
  {
   if(ArraySize()==0) 
      return(0);
   uint max_index=ArrayMaximum(array);  
   return(array[max_index]);
  }

bunu kaynak kodunuzda kullanabilmeniz için:

double high[];
datetime time[];
....
double max_high=ArrayMax(high);
datetime lasttime=ArrayMax(time);

Burada, kullanılan verinin tipini belirten T biçimsel parametresi, derleme esnasında gerçekte uygulanan tip ile değiştirilir. Yani derleyici herbir tip için ( double, datetime, vb) otomatik olarak bir fonksiyon oluşturur. MQL5 dili, yaklaşımın tüm avantajları ile sınıf sablonları oluşturmanıza olanak sağlar.

Sınıf şablonları

Sınıf şablonları template anahtar sözcüğü ve açı parantezlerle <>, typename anahtar sözcüğü ile biçimsel parametreler sıralanarak bildirilir. Bu girdi, bir sınıf uygulaması yaparken, bir reel değişkeni tanımlayan T biçimsel parametresi ile bir jenerik sınıf üzerinde çalışıldığı konusunda derleyiciyi bilgilendirir. Örnek olarak T tipli elemanlardan oluşan bir diziyi depolamak için bir vektör sınıfı oluşturalım:

#define TOSTR(x) #x+" "   // bir nesne ismini göstermek için makro
//+------------------------------------------------------------------+
//| T-tipi bileşenleri depolamak için bir vektör sınıfı              |
//+------------------------------------------------------------------+
template <typename T>
class TArray
  {
protected:
   T                 m_array[];
public:
   //--- yapıcı varsayılan olarak 10 elemanlı bir dizi oluşturur
   void TArray(void){ArrayResize(m_array,10);}
   //--- belirtilen dizi boyutuna göre dizi oluşturmak için bir yapıcı
   void TArray(int size){ArrayResize(m_array,size);}
   //--- TArray tipli nesnede depolanan verinin tipine ve miktarına dönüş yap 
   string Type(void){return(typename(m_array[0])+":"+(string)ArraySize(m_array));};
  };

Şimdi çeşitli veri tipleriyle çalışmak için farklı yöntemler kullanarak üç TArray nesnesi oluşturalım

void OnStart()
  {
   TArray<double> double_array;   // vektörün varsayılan boyutu 10 
   TArray<int> int_array(15);     // vectör boyutu 15
   TArray<string> *string_array;  // TArray<string> vector için işaretçi
//--- dinamik nesne oluştur
   string_array=new TArray<string>(20);
//--- nesne ismini veri tipini ve boyutunu günlükte görüntüle
   PrintFormat("%s (%s)",TOSTR(double_array),double_array.Type());
   PrintFormat("%s (%s)",TOSTR(int_array),int_array.Type());
   PrintFormat("%s (%s)",TOSTR(string_array),string_array.Type());
//--- program tamamlanmadan bir dinamik nesneyi sil
   delete(string_array);   
  }

Çalıştırılan betiğin sonuçları:

  double_array  (double:10)
  int_array  (int:15)
  string_array  (string:20)

Artık, farklı veri tiplerine sahip (double, int ve string) üç vektörümüz var.

Sınıf şablonları taşıyıcıların (farklı tiplerdeki nesneleri kapsüllemek için kullanılan nesneler) geliştirilmesi için uygundur. Taşıyıcı nesneler belli tipteki diğer nesneleri içerirler. Genellikle depolanan verilerle yapılan çalışmalar hemen taşıyıcıya eklenir.

Örneğin, dizi dışındaki elemanlara erişimi kısıtlayan bir sınıf şablonu oluşturabilir ve "kapsam dışı" kritik halarını önleyebilirsiniz.

//+------------------------------------------------------------------+
//| Bir dizi elamnına serbest erişim sağlayan bir sınıf              |
//+------------------------------------------------------------------+
template<typename T>
class TSafeArray
  {
protected:
   T                 m_array[];
public:
   //--- varsayılan yapıcı
   void              TSafeArray(void){}
   //--- belirtilen boyutta dizi oluştumak için yapıcı
   void              TSafeArray(int size){ArrayResize(m_array,size);}
   //--- dizi boyutu 
   int               Size(void){return(ArraySize(m_array));}
   //--- dizi boyutunu değiştir 
   int               Resize(int size,int reserve){return(ArrayResize(m_array,size,reserve));}
   //--- diziyi boşalt 
   void              Erase(void){ZeroMemory(m_array);}
   //--- indise göre dizi elemanına erişim sağlayan operatör
   T                 operator[](int index);
   //--- dizinin tüm elemanlarını tekseferde alabilmek için atama operatörü
   void              operator=(const T  &array[]); // T tipli dizi 
  };
//+------------------------------------------------------------------+
//| İndisine göre eleman alma                                        |
//+------------------------------------------------------------------+
template<typename T>
T TSafeArray::operator[](int index)
  {
   static T invalid_value;
//---
   int max=ArraySize(m_array)-1;
   if(index<0 || index>=ArraySize(m_array))
     {
      PrintFormat("%s, %d indisi (0-%d) kapsamında değil!",__FUNCTION__,index,max);
      return(invalid_value);
     }
//---
   return(m_array[index]);
  }
//+------------------------------------------------------------------+
//| Dizi için atama                                                  |
//+------------------------------------------------------------------+
template<typename T>
void TSafeArray::operator=(const T  &array[])
  {
   int size=ArraySize(array);
   ArrayResize(m_array,size);
//--- T tipi, kopyalama işlemini desteklemeli
   for(int i=0;i<size;i++)
      m_array[i]=array[i];
//---
  }
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
   int copied,size=15;  
   MqlRates rates[];
//--- fiyat dizisini kopyala
   if((copied=CopyRates(_Symbol,_Period,0,size,rates))!=size)
     {
      PrintFormat("CopyRates(%s,%s,0,%d) çağrısı %d hata koduna dönüş yaptı",
      _Symbol,EnumToString(_Period),size,GetLastError());
      return;
     }
//--- bir taşıyıcı oluşturup MqlRates dizisini ekle
   TSafeArray<MqlRates> safe_rates;
   safe_rates=rates;
   //--- dizi kapsamında bir indis
   int index=3;
   PrintFormat("Close[%d]=%G",index,safe_rates[index].close);
   //--- indis dizi kapsamı dışında
   index=size;
   PrintFormat("Close[%d]=%G",index,safe_rates[index].close);
  }

Şablon bildirimlerinin sınıf bildirimleri dışında yöntem tanımlarken de kullanılabileceğini not ediniz:

template<typename T>
T TSafeArray::operator[](int index)
  {
  ... 
  }
template<typename T>
void TSafeArray::operator=(const T  &array[])
  {
  ... 
  }

Sınıf ve fonksiyon şablonları, virgülle eyrılmış şekilde biçimsel parametreler kullanabilmenizi sağlar. Örneğin, "anahtar – değer" çiftlerini kaydetmek için bağıntılar:

template<typename Key, template Value>
class TMap
  {
  ... 
  }

 

Ayrıca bakınız

Fonksiyon şablonları, Aşırı Yükleme