Şablon Uzmanlığı (C++)

Sınıf şablonları kısmen özelleştirilebilir ve sonuçta elde edilen sınıf hala bir şablondur. Kısmi özelleştirme, şablon kodunun bazı durumlarda belirli türler için kısmen özelleştirilmesine olanak tanır, örneğin:

  • Bir şablonun birden çok türü vardır ve yalnızca bazılarının özel olması gerekir. Sonuç, kalan türlerde parametrelendirilmiş bir şablondur.

  • Şablonun yalnızca bir türü vardır, ancak işaretçi, başvuru, üye işaretçisi veya işlev işaretçisi türleri için bir özelleştirme gerekir. Özelleştirmenin kendisi, işaret edilen veya başvuruda bulunan türdeki bir şablondur.

Örnek: Sınıf şablonlarının kısmi uzmanlığı

// partial_specialization_of_class_templates.cpp
#include <stdio.h>

template <class T> struct PTS {
   enum {
      IsPointer = 0,
      IsPointerToDataMember = 0
   };
};

template <class T> struct PTS<T*> {
   enum {
      IsPointer = 1,
      IsPointerToDataMember = 0
   };
};

template <class T, class U> struct PTS<T U::*> {
   enum {
      IsPointer = 0,
      IsPointerToDataMember = 1
   };
};

struct S{};

int main() {
   printf_s("PTS<S>::IsPointer == %d \nPTS<S>::IsPointerToDataMember == %d\n",
           PTS<S>::IsPointer, PTS<S>:: IsPointerToDataMember);
   printf_s("PTS<S*>::IsPointer == %d \nPTS<S*>::IsPointerToDataMember == %d\n"
           , PTS<S*>::IsPointer, PTS<S*>:: IsPointerToDataMember);
   printf_s("PTS<int S::*>::IsPointer == %d \nPTS"
           "<int S::*>::IsPointerToDataMember == %d\n",
           PTS<int S::*>::IsPointer, PTS<int S::*>::
           IsPointerToDataMember);
}
PTS<S>::IsPointer == 0 
PTS<S>::IsPointerToDataMember == 0
PTS<S*>::IsPointer == 1 
PTS<S*>::IsPointerToDataMember == 0
PTS<int S::*>::IsPointer == 0 
PTS<int S::*>::IsPointerToDataMember == 1

Örnek: İşaretçi türleri için kısmi özelleştirme

Herhangi bir türü Talan bir şablon koleksiyonu sınıfınız varsa, herhangi bir işaretçi türünü T*alan kısmi bir özelleştirme oluşturabilirsiniz. Aşağıdaki kod, koleksiyon sınıfı şablonunu Bag ve koleksiyonun işaretçi türlerini diziye kopyalamadan önce başvuruda bulunduğu işaretçi türleri için kısmi özelleştirmeyi gösterir. Koleksiyon daha sonra işaret edilen değerleri depolar. Özgün şablonda, yalnızca işaretçilerin kendileri koleksiyonda depolanmış ve veriler silinmeye veya değişikliğe karşı savunmasız bırakılmıştır. Koleksiyonun bu özel işaretçi sürümünde, yönteminde add null işaretçi olup olmadığını denetlemek için kod eklenir.

// partial_specialization_of_class_templates2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

// Original template collection class.
template <class T> class Bag {
   T* elem;
   int size;
   int max_size;

public:
   Bag() : elem(0), size(0), max_size(1) {}
   void add(T t) {
      T* tmp;
      if (size + 1 >= max_size) {
         max_size *= 2;
         tmp = new T [max_size];
         for (int i = 0; i < size; i++)
            tmp[i] = elem[i];
         tmp[size++] = t;
         delete[] elem;
         elem = tmp;
      }
      else
         elem[size++] = t;
   }

   void print() {
      for (int i = 0; i < size; i++)
         cout << elem[i] << " ";
      cout << endl;
   }
};

// Template partial specialization for pointer types.
// The collection has been modified to check for NULL
// and store types pointed to.
template <class T> class Bag<T*> {
   T* elem;
   int size;
   int max_size;

public:
   Bag() : elem(0), size(0), max_size(1) {}
   void add(T* t) {
      T* tmp;
      if (t == NULL) {   // Check for NULL
         cout << "Null pointer!" << endl;
         return;
      }

      if (size + 1 >= max_size) {
         max_size *= 2;
         tmp = new T [max_size];
         for (int i = 0; i < size; i++)
            tmp[i] = elem[i];
         tmp[size++] = *t;  // Dereference
         delete[] elem;
         elem = tmp;
      }
      else
         elem[size++] = *t; // Dereference
   }

   void print() {
      for (int i = 0; i < size; i++)
         cout << elem[i] << " ";
      cout << endl;
   }
};

int main() {
   Bag<int> xi;
   Bag<char> xc;
   Bag<int*> xp; // Uses partial specialization for pointer types.

   xi.add(10);
   xi.add(9);
   xi.add(8);
   xi.print();

   xc.add('a');
   xc.add('b');
   xc.add('c');
   xc.print();

   int i = 3, j = 87, *p = new int[2];
   *p = 8;
   *(p + 1) = 100;
   xp.add(&i);
   xp.add(&j);
   xp.add(p);
   xp.add(p + 1);
   delete[] p;
   p = NULL;
   xp.add(p);
   xp.print();
}
10 9 8
a b c
Null pointer!
3 87 8 100

Örnek: Bir tür olacak şekilde kısmi özelleştirme tanımlayın int

Aşağıdaki örnek, herhangi iki türden oluşan çiftleri alan bir şablon sınıfı tanımlar ve sonra bu şablon sınıfının türlerden biri olacak intşekilde özelleştirilmiş kısmi bir özelleştirme tanımlar. Özelleştirme, tamsayıya göre basit bir kabarcık sıralama uygulayan ek bir sıralama yöntemi tanımlar.

// partial_specialization_of_class_templates3.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

template <class Key, class Value> class Dictionary {
   Key* keys;
   Value* values;
   int size;
   int max_size;
public:
   Dictionary(int initial_size) :  size(0) {
      max_size = 1;
      while (initial_size >= max_size)
         max_size *= 2;
      keys = new Key[max_size];
      values = new Value[max_size];
   }
   void add(Key key, Value value) {
      Key* tmpKey;
      Value* tmpVal;
      if (size + 1 >= max_size) {
         max_size *= 2;
         tmpKey = new Key [max_size];
         tmpVal = new Value [max_size];
         for (int i = 0; i < size; i++) {
            tmpKey[i] = keys[i];
            tmpVal[i] = values[i];
         }
         tmpKey[size] = key;
         tmpVal[size] = value;
         delete[] keys;
         delete[] values;
         keys = tmpKey;
         values = tmpVal;
      }
      else {
         keys[size] = key;
         values[size] = value;
      }
      size++;
   }

   void print() {
      for (int i = 0; i < size; i++)
         cout << "{" << keys[i] << ", " << values[i] << "}" << endl;
   }
};

// Template partial specialization: Key is specified to be int.
template <class Value> class Dictionary<int, Value> {
   int* keys;
   Value* values;
   int size;
   int max_size;
public:
   Dictionary(int initial_size) :  size(0) {
      max_size = 1;
      while (initial_size >= max_size)
         max_size *= 2;
      keys = new int[max_size];
      values = new Value[max_size];
   }
   void add(int key, Value value) {
      int* tmpKey;
      Value* tmpVal;
      if (size + 1 >= max_size) {
         max_size *= 2;
         tmpKey = new int [max_size];
         tmpVal = new Value [max_size];
         for (int i = 0; i < size; i++) {
            tmpKey[i] = keys[i];
            tmpVal[i] = values[i];
         }
         tmpKey[size] = key;
         tmpVal[size] = value;
         delete[] keys;
         delete[] values;
         keys = tmpKey;
         values = tmpVal;
      }
      else {
         keys[size] = key;
         values[size] = value;
      }
      size++;
   }

   void sort() {
      // Sort method is defined.
      int smallest = 0;
      for (int i = 0; i < size - 1; i++) {
         for (int j = i; j < size; j++) {
            if (keys[j] < keys[smallest])
               smallest = j;
         }
         swap(keys[i], keys[smallest]);
         swap(values[i], values[smallest]);
      }
   }

   void print() {
      for (int i = 0; i < size; i++)
         cout << "{" << keys[i] << ", " << values[i] << "}" << endl;
   }
};

int main() {
   Dictionary<const char*, const char*> dict(10);
   dict.print();
   dict.add("apple", "fruit");
   dict.add("banana", "fruit");
   dict.add("dog", "animal");
   dict.print();

   Dictionary<int, const char*> dict_specialized(10);
   dict_specialized.print();
   dict_specialized.add(100, "apple");
   dict_specialized.add(101, "banana");
   dict_specialized.add(103, "dog");
   dict_specialized.add(89, "cat");
   dict_specialized.print();
   dict_specialized.sort();
   cout << endl << "Sorted list:" << endl;
   dict_specialized.print();
}
{apple, fruit}
{banana, fruit}
{dog, animal}
{100, apple}
{101, banana}
{103, dog}
{89, cat}

Sorted list:
{89, cat}
{100, apple}
{101, banana}
{103, dog}