logo

Szablony w C++ z przykładami

A szablon to proste, ale bardzo potężne narzędzie w C++. Prostym pomysłem jest przekazanie typu danych jako parametru, abyśmy nie musieli pisać tego samego kodu dla różnych typów danych. Na przykład producent oprogramowania może potrzebować sort() dla różnych typów danych. Zamiast pisać i utrzymywać wiele kodów, możemy napisać jedną funkcję sort() i przekazać typ danych jako parametr.

C++ dodaje dwa nowe słowa kluczowe do obsługi szablonów: 'szablon' I 'Wpisz imię' . Drugie słowo kluczowe zawsze można zastąpić słowem kluczowym 'klasa' .



Jak działają szablony?

Szablony są rozwijane w czasie kompilatora. To jest jak makro. Różnica polega na tym, że kompilator sprawdza typ przed rozwinięciem szablonu. Pomysł jest prosty, kod źródłowy zawiera tylko funkcję/klasę, ale skompilowany kod może zawierać wiele kopii tej samej funkcji/klasy.

szablony-cpp

Szablony funkcji

Piszemy ogólną funkcję, której można używać dla różnych typów danych. Przykładami szablonów funkcji są sort(), max(), min(), printArray().

Aby dowiedzieć się więcej na ten temat zob Generics w C++ .



Przykład:

C++
// C++ Program to demonstrate // Use of template #include  using namespace std; // One function works for all data types. This would work // even for user defined types if operator '>' jest przeciążonym szablonemT myMax(T x, T y) { return (x> y) ? x: y; } int main() { // Wywołaj myMax dla int cout<< myMax (3, 7)<< endl;  // call myMax for double  cout << myMax(3,0, 7,0)<< endl;  // call myMax for char  cout << myMax('g', 'e')<< endl;  return 0; }>

Wyjście
7 7 g>

Przykład: Realizowanie Sortowanie bąbelkowe przy użyciu szablonów w C++

C++
// C++ Program to implement // Bubble sort // using template function #include  using namespace std; // A template function to implement bubble sort. // We can use this for any data type that supports // comparison operator  template void bubbleSort(T a[], int n) { for (int i = 0; tj< n - 1; i++)  for (int j = n - 1; i < j; j--)  if (a[j] < a[j - 1])  swap(a[j], a[j - 1]); } // Driver Code int main() {  int a[5] = { 10, 50, 30, 40, 20 };  int n = sizeof(a) / sizeof(a[0]);  // calls template function  bubbleSort (jakiś);  cout<< ' Sorted array : ';  for (int i = 0; i < n; i++)  cout << a[i] << ' ';  cout << endl;  return 0; }>

Wyjście
 Sorted array : 10 20 30 40 50>

Szablony klas

Szablony klas, takie jak szablony funkcji, szablony klas są przydatne, gdy klasa definiuje coś, co jest niezależne od typu danych. Może być przydatny w przypadku klas takich jak LinkedList, BinaryTree, Stack, Queue, Array itp.



Przykład:

operatory JavaScript
C++
// C++ Program to implement // template Array class #include  using namespace std; template klasa Tablica {prywatna: T* ptr;  rozmiar int; public: Array(T arr[], int s);  pusty wydruk(); }; szablonSzyk::Array(T arr[], int s) { ptr = nowe T[s];  rozmiar = s;  for (int i = 0; tj< size; i++)  ptr[i] = arr[i]; } template pusta tablica::print() { for (int i = 0; tj< size; i++)  cout << ' ' << *(ptr + i);  cout << endl; } int main() {  int arr[5] = { 1, 2, 3, 4, 5 };  Array a(arr, 5);  drukarka();  zwróć 0; }>

Wyjście
 1 2 3 4 5>

Czy może istnieć więcej niż jeden argument dla szablonów?

Tak, podobnie jak w przypadku normalnych parametrów, możemy przekazać więcej niż jeden typ danych jako argumenty do szablonów. Poniższy przykład pokazuje to samo.

Przykład:

C++
// C++ Program to implement // Use of template #include  using namespace std; template klasa A { Tx;  Ty; publiczny: A() { przysł<< 'Constructor Called' << endl; } }; int main() {  AA;  A B;  zwróć 0; }>

Wyjście
Constructor Called Constructor Called>

Czy możemy określić domyślną wartość argumentów szablonu?

Tak, podobnie jak w przypadku normalnych parametrów, możemy określić domyślne argumenty szablonów. Poniższy przykład pokazuje to samo.

Przykład:

C++
// C++ Program to implement // Use of template #include  using namespace std; template klasa A {publiczna: T x;  Ty;  A() {przym<< 'Constructor Called' << endl; } }; int main() {  // This will call A  AA;  zwróć 0; }>

Wyjście
Constructor Called>

Jaka jest różnica między przeciążaniem funkcji a szablonami?

Zarówno przeciążanie funkcji, jak i szablony są przykładami cech polimorfizmu OOP. Przeciążanie funkcji stosuje się, gdy wiele funkcji wykonuje całkiem podobne (nie identyczne) operacje, szablony są używane, gdy wiele funkcji wykonuje identyczne operacje.

Co się stanie, gdy w klasie/funkcji szablonu znajduje się element statyczny?

Każde wystąpienie szablonu zawiera własną zmienną statyczną. Widzieć Szablony i zmienne statyczne po więcej szczegółów.

Czym jest specjalizacja szablonów?

Specjalizacja szablonów pozwala nam mieć różne kody dla określonego typu danych. Widzieć Specjalizacja szablonowa po więcej szczegółów.

Czy możemy przekazywać parametry inne niż typ do szablonów?

Do szablonów możemy przekazywać argumenty inne niż typu. Parametry nietypowe są używane głównie do określania wartości maksymalnych i minimalnych lub dowolnej innej stałej wartości dla konkretnej instancji szablonu. Ważną rzeczą, na którą należy zwrócić uwagę w przypadku parametrów nietypowych, jest to, że muszą one być stałe. Kompilator musi znać wartość parametrów innych niż typ w czasie kompilacji. Ponieważ kompilator musi utworzyć funkcje/klasy dla określonej wartości innej niż typ w czasie kompilacji. Jeśli w poniższym programie zastąpimy 10000 lub 25 zmienną, otrzymamy błąd kompilatora.

Przykład:

transmisja medialna
C++
// C++ program to demonstrate // working of non-type parameters // to templates in C++ #include  using namespace std; template int arrMin(T arr[], int n) { int m = max;  for (int i = 0; tj< n; i++)  if (arr[i] < m)  m = arr[i];  return m; } int main() {  int arr1[] = { 10, 20, 15, 12 };  int n1 = sizeof(arr1) / sizeof(arr1[0]);  char arr2[] = { 1, 2, 3 };  int n2 = sizeof(arr2) / sizeof(arr2[0]);  // Second template parameter  // to arrMin must be a  // constant  cout << arrMin (tablica1, n1)<< endl;  cout << arrMin(tablica2, n2);    zwróć 0; }>

Wyjście
10 1>

Oto przykład programu w C++ pokazującego różne typy danych przy użyciu konstruktora i szablonu. Wykonamy kilka czynności

  • przekazywanie wartości znaku poprzez utworzenie obiektu w funkcji main().
  • przekazanie wartości całkowitej poprzez utworzenie obiektu w funkcji main().
  • przekazywanie wartości zmiennoprzecinkowej poprzez utworzenie obiektu w funkcji main().

Przykład:

C++
// C++ program to show different data types using a // constructor and template. #include  using namespace std; // defining a class template template class info { public: // konstruktor typu szablon info(TA) { cout<< '
'  << 'A = ' << A  << ' size of data in bytes:' << sizeof(A);  }  // end of info() }; // end of class // Main Function int main() {  // clrscr();  // passing character value by creating an objects  infop('x');  // przekazanie wartości całkowitej poprzez utworzenie informacji o obiekcie q(22);  // przekazanie wartości float poprzez utworzenie informacji o obiekcier(2,25);  zwróć 0; }>

Wyjście
A = x size of data in bytes:1 A = 22 size of data in bytes:4 A = 2.25 size of data in bytes:4>

Odliczenie argumentów szablonowych

Odliczanie argumentów szablonu automatycznie określa typ danych argumentu przekazanego do szablonów klasy lub funkcji. Dzięki temu możemy utworzyć instancję szablonu bez jawnego określania typu danych.

Rozważmy na przykład poniższy szablon funkcji, aby pomnożyć dwie liczby:

template  t multiply (t num1,t num2) { return num1*num2; }>

Ogólnie rzecz biorąc, gdy chcemy użyć funkcji multiply() dla liczb całkowitych, musimy wywołać ją w ten sposób:

multiply (25, 5);>

Ale możemy to też nazwać:

multiply(23, 5);>

Nie określamy jawnie typu, np. 1,3 to liczby całkowite.

To samo dotyczy klas szablonów (tylko od C++ 17). Załóżmy, że definiujemy klasę szablonów jako:

template class student{  private:  t total_marks;  public:  student(t x) : total_marks(x) {} };>

Jeśli chcemy utworzyć instancję tej klasy, możemy zastosować dowolną z następujących składni:

postać normalna Greibacha
student stu1(23);    or  student stu2(24);>

Notatka: Należy zauważyć, że odliczanie argumentów szablonu dla klas jest dostępne tylko od C++ 17, więc jeśli spróbujemy użyć automatycznego odejmowania argumentów szablonu dla klasy w poprzedniej wersji, zgłosi błąd.

Przykład odliczenia argumentów szablonowych

Poniższy przykład ilustruje, w jaki sposób szablon klasy wektora STL dedukuje typ danych bez jawnego określenia.

C++
// C++ Program to illustrate template arguments deduction in // STL #include  #include  using namespace std; int main() {  // creating a vector object without specifying  // type  vector v1{ 1.1, 2.0, 3.9, 4.909 };  cout << 'Elements of v1 : ';  for (auto i : v1) {  cout << i << ' ';  }  // creating a vector object without specifying type  vector v2{ 1, 2, 3, 4 };  cout << endl << 'Elements of v2 : ';  for (auto i : v2) {  cout << i << ' ';  } }>


Wyjście

Elements of v1 : 1.1 2 3.9 4.909  Elements of v2 : 1 2 3 4>

Notatka: Powyższy program nie powiedzie się w kompilacji w C++ 14 i niższych kompilatorach, ponieważ w C++ 17 dodano dedukcję argumentów szablonu klasy.

Odliczenie argumentów szablonu funkcji

Odliczanie argumentów szablonu funkcji jest częścią C++ od czasu standardu C++ 98. Możemy pominąć deklarowanie typu argumentów, które chcemy przekazać do szablonu funkcji, a kompilator automatycznie wydedukuje typ na podstawie argumentów, które przekazaliśmy w wywołaniu funkcji.

Przykład: W poniższym przykładzie pokazujemy, jak funkcje w C++ automatycznie określają swój typ.

C++
// C++ program to illustrate the function template argument // deduction #include  using namespace std; // defining function template template t pomnóż(t pierwszy, t drugi) { zwróć pierwszy * drugi; } // kod sterownika int main() { auto wynik = multiply(10, 20);  std::cout<< 'Multiplication OF 10 and 20: ' << result  << std::endl;  return 0; }>

Wyjście
Multiplication OF 10 and 20: 200>

Notatka: W przypadku szablonów funkcji, które mają ten sam typ argumentów, np. szablonowa funkcja void(t a1, t a2){}, nie możemy przekazywać argumentów różnych typów.

wyśrodkuj obraz w CSS

Odliczenie argumentów szablonu klasy (C++ 17 i nowsze)

Dedukcja argumentów szablonu klasy została dodana w C++ 17 i od tego czasu jest częścią tego języka. Pozwala nam tworzyć instancje szablonów klas bez jawnego definiowania typów, podobnie jak szablony funkcji.

Przykład: W poniższym przykładzie pokazujemy, jak kompilator automatycznie klasyfikuje szablony w C++.

C++
// C++ Program to implement Class Template Arguments // Deduction #include  #include  #include  using namespace std; // Defining class template template uczeń klasy { prywatny: string nazwa_ucznia;  T suma_znaków; public: // Sparametryzowany konstruktor student(string n, T m): student_name(n) , total_marks(m) { } void getinfo() { // wydruk szczegółów ucznia cout<< 'STUDENT NAME: ' << student_name << endl;  cout << 'TOTAL MARKS: ' << total_marks << endl;  cout << 'Type ID: ' << typeid(total_marks).name()  << endl;  } }; int main() {  student s1('Vipul', 100); // Deduces student  student s2('Yash', 98.5); // Deduces student  s1.getinfo();  s2.getinfo();  return 0; }>


Wyjście

STUDENT NAME: Vipul TOTAL MARKS: 100 Type ID: i STUDENT NAME: Yash TOTAL MARKS: 98.5 Type ID: d>

Tutaj i oznacza int, a d oznacza double.

W przypadku metaprogramowania szablonów r odsyłamy do następnego artykułu – Metaprogramowanie szablonów .

Weź Quiz dotyczący szablonów . Java również obsługuje te funkcje. Java to nazywa leki generyczne .