Share via


Sjabloonspecialisatie (C++)

Klassesjablonen kunnen gedeeltelijk gespecialiseerd zijn en de resulterende klasse is nog steeds een sjabloon. Met gedeeltelijke specialisatie kan sjablooncode gedeeltelijk worden aangepast voor specifieke typen in situaties, zoals:

  • Een sjabloon heeft meerdere typen en slechts enkele hiervan hoeven gespecialiseerd te zijn. Het resultaat is een sjabloon die is geparameteriseerd voor de resterende typen.

  • Een sjabloon heeft slechts één type, maar er is een specialisatie nodig voor aanwijzer, verwijzing, aanwijzer naar lid- of functiepointertypen. De specialisatie zelf is nog steeds een sjabloon voor het type waarnaar wordt verwezen of waarnaar wordt verwezen.

Voorbeeld: Gedeeltelijke specialisatie van klassesjablonen

// 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

Voorbeeld: Gedeeltelijke specialisatie voor aanwijzertypen

Als u een sjabloonverzamelingsklasse hebt die elk type Tgebruikt, kunt u een gedeeltelijke specialisatie maken die elk type aanwijzer T*gebruikt. De volgende code demonstreert een verzamelingsklassesjabloon Bag en een gedeeltelijke specialisatie voor aanwijzertypen waarin de verzameling de aanwijzertypen deducteert voordat deze naar de matrix worden gekopieerd. De verzameling slaat vervolgens de waarden op waarnaar wordt verwezen. Met de oorspronkelijke sjabloon zouden alleen de aanwijzers zelf zijn opgeslagen in de verzameling, waardoor de gegevens kwetsbaar zijn voor verwijdering of wijziging. In deze speciale aanwijzerversie van de verzameling wordt code toegevoegd om te controleren op een null-aanwijzer in de add methode.

// 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

Voorbeeld: Gedeeltelijke specialisatie definiëren, zodat één type is int

In het volgende voorbeeld wordt een sjabloonklasse gedefinieerd die paren van twee typen accepteert en vervolgens een gedeeltelijke specialisatie van die sjabloonklasse definieert, zodat een van de typen is int. De specialisatie definieert een extra sorteermethode waarmee een eenvoudige bellensorteerd wordt geïmplementeerd op basis van het gehele getal.

// 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}